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 发布

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

目前当这种情况下发生时,递归访问seq返回nil。这导致代码似乎在正常工作,但实际上产生错误结果,或者甚至错误的代码也由于运气而产生了正确的结果(参见https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion中的示例)。

因此,这个补丁会调整LazySeq状态(f, sv 和 s 字段)在所有可能递归调用的之前(.seq 中的 .sval 和.sval中的 .invoke),以便在重新进入时,LazySeq 状态是一致的,并且能传达出seq已经被计算的事实。

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

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

有了这个补丁
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非空|空|空|
|实现|空|空|除了这个以外的任何内容|
|正在实现|空|空|这个|

0

评论者:jafingerhut

最后一个评论,Christophe,对我解释这个想法有意义。能否将类似内容的评论作为补丁的一部分添加?

0

评论由:cgrand 发布

带有说明预期状态的补丁。
注意:我对状态表进行了整理。

// 在调用用户代码之前(sval中的f.invoke()以及在segue中的((LazySeq)ls).sval(),甚至在序列中的RT.seq())确保LazySeq状态处于以下状态之一:// // 状态 f sv // ======================== // 未实现 非空 空白 // 实现空白空白 // 正在实现空白这个//

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
用户=> (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
用户=> (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 报告)
...