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

欢迎!请查看关于页面以获取更多关于此如何工作的信息。

0投票
Clojure
如果用指引该变量的延迟序列定义全局数据变量,你可以根据构建集合的函数的延迟碎片性不同得到不同的结果。

Clojure 的延迟序列不支持此操作,但它们不应该返回错误的答案。在http://groups.google.com/group/clojure/browse_thread/thread/1c342fad8461602d中给定的示例(见下方),Clojure 不应该返回错误数据。错误信息会更好,甚至无限循环也比当前的行为更合理。

(同类问题在此报道:https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion)

(def nums (drop 2 (range Long/MAX_VALUE)))
(def primes (cons (first nums')
             (lazy-seq (->>
               (rest nums')
               (remove
                   (fn [x]
                     (let [dividors (take-while #(<= (* % %) x)
primes)]
                     (println (str "primes = " primes))
                     (some #(= 0 (rem x %)) dividors)))))))))
(take 5 primes)

它输出
(primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
2 3 5 7 9)

13 答案

0投票

评论由:importer 提出

http://www.assembla.com/spaces/clojure/tickets/457 转换而来

0投票
by

评论人:aaron

Stu 和 Rich 讨论过将其视为错误,但这会破坏一些现有代码。

0投票
by

评论人:richhickey

对于这个问题您有具体的疑问吗?

0投票
by

评论人:aaron

Stu,我和你讨论过这个问题,但我不记得具体是什么问题了。

0投票
by

评论人:cgrand

附带了一个初步补丁。
有没有示例代码表示这样的补丁(如 Aaron Bedra 所提及的)破坏了现有代码?

0投票
by

评论人:richhickey

补丁的目的是做什么?我们只有问题描述和代码。请列出计划,而不是让我们去解析补丁。

作为一个基本原则,我不想让 Clojure 承诺这样的递归定义的值是可能的。

0投票
by

评论人:cgrand

本提案建议捕捉递归 seq 实现时(即在计算 lazy-seq 的主体时尝试访问同一 seq),并抛出异常。

目前在这种情况下,对seq的递归访问返回nil。这导致代码看似在正常工作,但实际上产生错误的结果,甚至有可能产生错误代码却由于运气产生了正确的结果(参阅https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion以获取此类示例)。

因此,此补丁在所有潜在的递归方法调用之前(.seq的while中的.sval和.sval中的.invoke)对LazySeq状态(f、sv和s字段)的更改进行移动,以便在重新进入时,LazySeq的状态保持一致,并且能够传达seq已经开始计算的事实。

目前,递归调用可能会发现f和sv被清除,并得出结论计算已完成,结果在s中,尽管s尚未受到影响。

目前
状态 f sv s
| :-- | :-- | :-- | :-- | :-- |
未实现 非空 null null
实现中 null null 任何东西
正在实现中的/from fn.invoke 不为空 null null
正在实现中的/from ls.sval null null null
注意,“正在实现中”状态与“未实现”或“实现中”重叠。
(注:“任何东西”包括null)

使用补丁
状态 f sv s
| :-- | :-- | :-- | :-- | :-- |
未实现 非空 null null
实现中 null null 除了这个之外任何东西
正在实现中 null 这个

0投票

评论人:jafingerhut

最后那条评论,Christophe,对我解释这个想法有相当大的帮助,至少对我来说如此。能否在补丁中添加类似内容的评论?

0投票

评论人:cgrand

補丁包括解释预期状态的注释。
注:我已经整理了状态表。

在调用用户代码之前(sval中的f.invoke()和,间接地,seq中的((LazySeq)ls).sval() — 甚至是seq中的RT.seq()),确保LazySeq状态处于以下状态之一: // // 状态 f sv // ================================ // 未实现 非空 null null // 实现中 null null // 正在实现中 null 这个

此补丁还解决了CLJ-1119的问题。

0投票

评论人:jafingerhut

Patch clj-457-3.diff与Christophe的CLJ-457-2.diff完全相同,但它已经被更新以不再与2013年11月22日为CLJ-949做出的提交冲突,该提交基本上移除了sval()方法中的try/catch。它通过测试,我没有看到任何问题,但是克里斯托夫再看看也会很好。

0投票

评论者:alexmiller

已不再可重现。

0投票
_评论者:bronsa_

Alex,已发布的示例无法再复现,因为 `(range)` 不再产生分块序列。
另一方面,`(range n)` 可以这样做,只需将票证描述中的代码示例中的 `(range)` 替换为类似于 `(range Long/MAX_VALUE)` 即可重新出现此故障




Clojure 1.8.0-master-SNAPSHOT
user> (def nums (drop 2 (range Long/MAX_VALUE)))
#'user/nums
(def primes (cons (first nums')
             (lazy-seq (->>
               (rest nums')
               (remove
                   (fn [x]
                     (let [dividors (take-while #(<= (* % %) x)
primes)]
                     (println (str "primes = " primes))
                     (some #(= 0 (rem x %)) dividors)))))))))
#'user/primes
user> (take 5 primes)
(primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
primes = (2)
2 3 5 7 9)

0投票
参考:https://clojure.atlassian.net/browse/CLJ-457(由 alex+import 报告)
...