Clojure の lazy-seq

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も使ってないからなんとなくしっくり来ない。関数の定義は再帰呼び出しの形ではあるけど、呼び出したときに、全ての要素を評価しないから、スタックオーバーフローもしないということのようです。

3件のコメント

  • ter アレッシィ

  • Crystal Clear iPhone

  • rtz Silver W atch

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です


The reCAPTCHA verification period has expired. Please reload the page.

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください