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

欢迎!请查看关于页面,了解更多关于这个工作方式的信息。

+1
Clojure

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

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

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

这可以在 {{mapcat}} 中修复,或者通过添加一个新的函数(到 {{clojure.core}}?)作为一个非变长的等价函数,并用它来重新实现 {{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。

(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 会导致对 'x' 的 '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 报告)
...