2024 Clojure 状态调查中分享你的想法!

欢迎!请查看关于页面以获取更多有关这一机制的信息。

+1 投票
Clojure

以下表达式打印{{1234}}并返回{{1}}

(first (mapcat #(do (print %) [%]) '(1 2 3 4 5 6 7)))

原因是{{(apply concat args)}}在它的参数上并不是最大程度上的惰性,实际上会在返回第一个项目之前实现前四个。这对于一个可变参数的{{concat}}来说是不可避免的。

这可以通过仅在{{mapcat}}中修复,或者通过添加一个新的函数(到{{clojure.core}}?)来修复,该函数是{{concat}}的非可变参数等效形式,并使用它重新实现{{mapcat}}。

(defn join "惰性地将序列的序列连接到一个平坦序列。" [s] (lazy-seq (when-let [[x & xs] (seq s)] (concat x (join xs)))))

6 答案

0 投票
_评论由:gfredericks_发表

我意识到,如果{{concat}}有一个单独的[& args]子句,并且像上面的{{join}}一样实现,那么可以使其更加懒惰而无需更改其语义。
0 投票

评论由:eigenhombre 发表

我上个月失去了几个小时来解决这个问题(链接:1、2)......今在Jira中看到这个票据...+1。

(链接:1) http://eigenhombre.com/2013/07/13/updating-the-genome-decoder-resulting-consequences/

(链接:2) http://clojurian.blogspot.com/2012/11/beware-of-mapcat.html

0 投票

评论者:gfredericks

更新代码使其实际有效。

0 投票

评论者:gshayban

描述中的join版本也不是最大化的惰性,它将实现两个底层集合。原因是:对seq进行解构会导致对'x'的'nth'调用和对'xs'的'nthnext'调用。nthnext不是最大化的惰性。

`
(defn join
"将一系列序列的序列惰性地连接成一个扁平序列。"
[s]
(lazy-seq
(when-let [s (seq s)]

 (concat (first s) (join (rest s))))))

`

0 投票

评论者:gshayban

尽管文档字符串没有作出惰性的承诺(除了声明它的特定实现),这似乎是一个缺陷,而不是一个增强。mapcat至少实现了四个底层集合

`
boot.user=> (defn notifying-seq [cb!] (lazy-seq (cb!) (cons :ignored (notifying-seq cb!))))

'boot.user/notifying-seq

boot.user=> (let [a (atom 0)]
(seq (mapcat (constantly [:ignored :ignored])

           (notifying-seq #(swap! a inc))))

@a)
4
`

0 投票
参考:https://clojure.atlassian.net/browse/CLJ-1218(由gfredericks报告)
...