这种行为的原因是最简单情况下的map
函数实现。(map f colls)
看到不同:
user=> (def b (lazy-cat [0] (map (fn [i _] (inc (nth b i))) (range) (range))))
#'user/b
user=> (take 5 b)
(0 1 2 3 4)
这有点令人困惑,但让我解释一下发生了什么。那么,为什么要map
改变行为的第二个论点:
https://github.com/clojure/clojure/blob/master/src/clj/clojure/core.clj#L2469
(defn map
...
([f coll]
(lazy-seq
(when-let [s (seq coll)]
(if (chunked-seq? s)
(let [c (chunk-first s)
size (int (count c))
b (chunk-buffer size)]
(dotimes [i size]
(chunk-append b (f (.nth c i))))
(chunk-cons (chunk b) (map f (chunk-rest s))))
(cons (f (first s)) (map f (rest s)))))))
([f c1 c2]
(lazy-seq
(let [s1 (seq c1) s2 (seq c2)]
(when (and s1 s2)
(cons (f (first s1) (first s2))
(map f (rest s1) (rest s2)))))))
...
答:优化的原因chunked-seq
。
user=> (chunked-seq? (seq (range)))
true
因此,值将被“预先计算”:
user=> (def b (lazy-cat [0] (map print (range))))
#'user/b
user=> (take 5 b)
(0123456789101112131415161718192021222324252627282930310 nil nil nil nil)
当然,在你的情况下,这个“预先计算”失败了IndexOutOfBoundsException
。