2007/07/22

[Common Lisp] series

series ってあまり使われてないのでしょうか?
CLtL2 の付録に載っています。
遅延評価を提供していてなかなか面白いのにな。
collect-file と scan-file の引数の external-format を追加しようとして挫折しました。
時間があるときにまたチャレンジしてみます。

それはさておき、ファイルの内容を標準出力に出すコードです。体裁を気にしないのなら (series:scan-file "cookbook.html" #'read-line) だけで各行が要素になっている頭に #Z が付いたリストが返ってきます。#Z はシリーズのディスパッチングマクロ文字になります。
シリーズは遅延評価されるので、ファイル全体を読み込んで出力ではなく、ちゃんと1行毎に read-line, write-line が行われます。


(require :series)
(series:collect-stream
*standard-output*
(series:scan-file "cookbook.html" #'read-line)
#'write-line)
;; この方が分かりやすいでしょうか
(let ((in (series:scan-file "cookbook.html" #'read-line)))
(series:collect-stream *standard-output* in #'write-line))

ちなみに、上の方のコードをマクロ展開すると次のようになります。tagbody と go が出てきました。CL です。

(LET* (#:ITEMS-1924 (#:DONE-1925 (LIST NIL)))
(WITH-OPEN-FILE (#:FILE-1922 "cookbook.html" :DIRECTION :INPUT)
(TAGBODY
#:LL-1928
(IF
(EQ
(SETQ #:ITEMS-1924 (FUNCALL #'READ-LINE #:FILE-1922 NIL #:DONE-1925))
#:DONE-1925)
(GO SERIES::END))
(FUNCALL #'WRITE-LINE #:ITEMS-1924 *STANDARD-OUTPUT*)
(GO #:LL-1928)
SERIES::END))
NIL)

下の方のコードをマクロ展開すると次のようになります。let でいったん束縛しているので、generator なるものが出てきます。使われ方によって異なる展開のされ方をするマクロなんてすごいですよね。このあたりが external-format 追加挫折の原因ではありますが。。。

(LET ((IN (SERIES:SCAN-FILE "cookbook.html" #'READ-LINE)))
(LET* ((#:OUT-1931 IN))
(LET ((#:GENERATOR-1934 (SERIES:GENERATOR #:OUT-1931)) #:ITEMS-1929)
(DECLARE (TYPE SERIES:GENERATOR #:GENERATOR-1934))
(TAGBODY
#:LL-1935
(SETQ #:ITEMS-1929
(SERIES::DO-NEXT-IN #:GENERATOR-1934
#'(LAMBDA () (GO SERIES::END))))
(FUNCALL #'WRITE-LINE #:ITEMS-1929 *STANDARD-OUTPUT*)
(GO #:LL-1935)
SERIES::END)
NIL)))

0 件のコメント: