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

欢迎!请查阅关于页面获取更多有关如何使用本站的信息。

+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 "将序列-of-sequences惰性连接成一个平坦的序列。" [s] (lazy-seq (when-let [[x & xs] (seq s)] (concat x (join xs)))))

6 个答案

0
_由gfredericks发表评论

我意识到,如果没有改变其语义,可以通过有单个 {{[& args]}} 子句使 {{concat}} 实际上更懒惰,然后像上面所述的 {{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

将 {{join}} 代码更新为实际有效。

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

尽管 docstring 没有关于惰性的承诺(除了声明特定的实现),这似乎是一个缺陷,而不是一个改进。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报告)
...