gpt4 book ai didi

Clojure无限惰性序列,越界

转载 作者:行者123 更新时间:2023-12-02 18:43:06 25 4
gpt4 key购买 nike

我最近才开始学习 Clojure,所以很抱歉,如果这有点初级:

有人可以向我解释一下两者之间的区别吗:

=> (def a (lazy-cat
[0]
(map inc a)
))

=> (take 5 a)
(0 1 2 3 4)

=> (def b (lazy-cat
[0]
(map #(inc (nth b %)) (range))
))

=> (take 5 b)

IndexOutOfBoundsException clojure.lang.RT.nthFrom (RT.java:773)

我期望第二个示例以相同的方式运行,使用 b 的第一个元素计算第二个元素,然后使用第二个元素计算第三个元素。我的理解是,clojure 甚至不会尝试计算 b 的第三个元素,直到它已经为第二个元素分配了一个值并将其打印在屏幕上。

我希望有人能解释一下这里幕后实际发生的事情。

谢谢:)

最佳答案

此行为的原因是最简单的 (map f colls) 情况下的 map 函数实现。查看差异:

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 失败。

关于Clojure无限惰性序列,越界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14283330/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com