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

欢迎!请查看关于页面以获取更多关于这个网站如何运作的信息。

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
by

评论者:richhickey

对此有具体问题吗?

0
by

评论者:aaron

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

0
by

评论者:cgrand

附上一个初步补丁。
Aaron Bedra提到,您有现有的被此补丁破坏的代码示例吗?

0
by

评论者:richhickey

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

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

0
by

评论者:cgrand

在此提议中,将捕获递归序列实现(即当尝试计算lazy-seq的主体时访问相同的序列)并抛出异常。

当前在这种情况下,递归访问序列返回nil。这导致看似工作但产生错误结果的代码,或者偶然产生正确结果的错误代码(请参阅https://groups.google.com/d/topic/clojure/yD941fIxhyE/discussion中的此类示例)。

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

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

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

随着补丁
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非null|null|null|
|已实现|空值|空值|除了这个以外的任何事物|
|正在实现|空值|空值|这个|

0

评论由:jafingerhut发表

previous评论Christophe对于概念的阐述对我来说至关重要,任何相似内容的评论能否作为补丁的一部分加入?

0

评论者:cgrand

包含解释期望状态的补丁。
注意:我已经整理了状态表。

// 在调用用户代码(如在sval中的f.invoke(),以及在seq中通过((LazySeq)ls).sval()(间接地)和(seq中的RT.seq()))之前,确保LazySeq的状态处于以下状态之一:// // 状态 f sv // ================================ // 未实现 not null null // 已实现 null null // 正在实现 null this

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

0

评论由:jafingerhut发表

补丁clj-457-3.diff与Christophe的CLJ-457-2.diff相同,但其已更新,不再与2013年11月22日为CLJ-949所做的提交冲突,主要是在方法sval()中删除了try/catch。它通过了测试,我看不出任何问题,但最好让Christophe也看一下。

0

评论由: alexmiller发布

不再可重现

0
评论由: bronsa_发表

Alex,发布的数据示例不再可重现,因为`(range)`不再产生分块序列。
另一方面,将`(range)`替换为 مانند `(range Long/MAX_VALUE)` 等在门票描述中的代码示例是足以重新出现bug的。




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 报告)
...