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 "惰性地将序列-of-序列连接到一个扁平序列。" [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。

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

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

0

评论者:gfredericks

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

0

评论者:gshayban

描述中的join版本也不是最大化的惰性版本,并且将实现两个底层集合。原因:对seq的结果进行解构时,调用的是xn的'nth'和'xs'的'nthnext'。nthnext不是最大化的惰性。

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

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

`

0

评论者:gshayban

虽然文档字符串没有做出任何关于惰性的承诺(除了声明其特定的实现),但这似乎是一个缺陷,而不是增强。mapcat至少实现了4个底层集合

`
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 报告)
...