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

评论文由:aaron撰写

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

0

评论文由:richhickey撰写

关于这个问题有具体的问题吗?

0

评论文由:aaron撰写

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

0

评论文由:cgrand撰写

附上了初步的补丁。
有现有代码会因为这样的补丁而出错(如Aaron Bedra所提及的)的例子吗?

0

评论文由:richhickey撰写

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

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

0

评论文由:cgrand撰写

这里的建议是捕获递归序列实现(即当计算懒序列的体时尝试访问同一个序列)并抛出异常。

目前,当这种情况发生时,递归访问序列返回nil。这导致看似正常但产生错误结果或出于偶然产生正确结果的代码(见https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion中的示例)。

因此,这个补丁在所有可能递归的方法调用之前(.seq中的.sval和.sval中的.invoke)对LazySeq状态(f,sv和s字段)的修改进行调整,以确保重入时LazySeq的状态是一致的,并能传达seq已经开始计算的事实。

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

目前
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非空|null|null|
|已实现|null|null|任何内容|
|正在实现/从fn.invoke发起的递归调用|null|null|null|
|正在实现/从ls.sval发起的递归调用|null|null|null|
请注意,“正在实现”状态与未实现或已实现重叠。
(注:“任何内容”包括null)

有了这个补丁
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非空|null|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 这个

这个补丁也修复了CLJ-1119。

0

评论者:jafingerhut

patch clj-457-3.diff与Christophe的CLJ-457-2.diff相同,但它已被更新以不再与2013年11月22日为CLJ-949所做的提交冲突,该提交基本上删除了sval()方法中的try/catch。它已通过测试,我没有看到任何问题,但最好Christophe也能检查一下。

0

评论者:alexmiller

不再可重现

0
评论者:bronsa_

亚历克斯,所发布的示例无法再重现,因为 `(range)` 已不再生成分块序列。
另一方面,将票证描述中的代码示例中的 `(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](https://clojure.atlassian.net/browse/CLJ-457)(由 alex+import 报告)
...