Clojure の lazy-seq
2010/10/28
lazy-seq を使ったことがなかったんですが、ちょっとしたことから無限シーケンスを作ってみたくなって、その経緯でlazy-seqを使ってみた。
(defn increment-list [n] (lazy-seq (cons n (increment-list (+ n 1))))) (print (increment-list 1)) ;=> 1 2 3 4 .... ずっと表示される。止まらない… (print (take 10 (increment-list 1))) ;=> 1 2 3 4 5 6 7 8 9 10 |
(increment-list 1)の結果としては無限シーケンスが生成される。しかし評価が遅延されているので、当然無限のシーケンスが生成されている訳ではない(領域確保的な意味で)。しかし、printしようとすると、無限シーケンスを最後まで評価しようとしてしまうので、延々と評価しつづける。takeで、最初の10個だけを評価すれば、10までの数字が表示されてそこで処理が止まる。
何気なく使っているmapの戻り値のシーケンスもlazyとなっている。ということで試してみたら、mapも無限シーケンスを引数に取ることもできた。
(print (take 10 (map #(str %) (increment-list 1)))) ;=> ("1" "2" "3" "4" "5" "6" "7" "8" "9" "10") |
これは面白いと思った。
そう言えば、increment-listの定義は、再帰呼び出しになっているけど、末尾再帰の形にもなってないし、recurも使ってないからなんとなくしっくり来ない。関数の定義は再帰呼び出しの形ではあるけど、呼び出したときに、全ての要素を評価しないから、スタックオーバーフローもしないということのようです。
ter アレッシィ
Crystal Clear iPhone
rtz Silver W atch