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 " Lazily concatenates a sequence-of-sequences into a flat sequence." [s] (lazy-seq (when-let [[x & xs] (seq s)] (concat x (join xs)))))

6 个答案

0
_评论由:gfredericks_

我意识到,如果{{concat}}有一个单一的{{[& args]}}子句,那么可以不改变其语义而使它变得更加懒惰。
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

虽然文档字符串没有做出任何懒惰承诺(除了声明其特定实现),但这看起来更像是一个缺陷而不是一个增强。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报告)
...