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。

(链接: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至少实现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报告)
...