Clojure惰性序列用法
我很难理解如何在Clojure中创build一个惰性序列。
macros的文档并不完全清楚:
用法:(lazy-seq&body)获取返回ISeq或nil的expression式体,并产生一个Seqable对象,只有在第一次调用seq时才会调用主体,并caching结果并将其返回到所有后续seq电话。
我见过的所有例子似乎都是这样的:
; return everything in the sequence starting at idx n (defn myseq-after-n [n] (...) ) (def my-lazy-seq (lazy-seq (conj [init-value] (myseq-after-n 2))) )
所以,我没有得到的第一件事是,因为lazy-seq在conj的调用之外,它如何防止conj在评估中产生一个无限序列?
我的第二个问题是,懒惰的序列定义总是采取这种一般forms?
lazy-seq调用只是在第一次访问时执行主体,然后在将来再次调用时caching并返回相同的结果。
如果你想用这个来构build长(甚至是无限)的序列,那么你需要在返回的序列中recursion嵌套其他lazy-seq调用。 以下是我能想到的最简单的情况:
(defn ints-from [n] (cons n (lazy-seq (ints-from (inc n))))) (take 10 (ints-from 7)) => (7 8 9 10 11 12 13 14 15 16)
任何(ints-from n)调用都会产生一个以n开始的序列,然后是一个惰性序列(ints-from(inc n))。 这是一个无限的列表,但这不是问题,因为lazy-seq确保(int-from(inc n))只在需要时被调用。 你可以尝试完全相同的代码没有lazy-seq,你会很快得到一个StackOverflowError。
lazy-seq只是创build懒惰序列的许多可能方法之一,而且往往不是最方便的。 以下是一些其他有趣的/有用的方法来创build懒序列:
; range is an easy way to get an infinite lazy sequence of integers, starting with zero (take 10 (range)) => (0 1 2 3 4 5 6 7 8 9) ; map produces lazy sequences, so the following is lazy (take 10 (map #(* % %) (range))) => (0 1 4 9 16 25 36 49 64 81) ; iterate is a good way of making infinite sequenes of the form x, f(x), f(f(x))..... (take 10 (iterate (partial * 2) 1)) => (1 2 4 8 16 32 64 128 256 512)