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 投票

评论由:导入器制作

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以获取此类示例)。

因此,此补丁将 LazySeq 状态(f、sv 和 s字段)的修改移动到所有潜在的递归方法调用之前(.seq 中的 .sval 和 .sval 中的 .invoke),以便在重新进入时,LazySeq的状态保持一致,并能传达序列正在被计算的事实。

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

目前
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非空|null|null|
|已实现|null|null|任何内容|
|正在实现/来自 fn.invoke 的递归调用|非空|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() 和,间接地,'((LazySeq)ls).sval()' 中的 seq -- 以及 seq 中的 RT.seq() -- 确保 LazySeq 状态处于以下状态之一: // // 状态 f sv //&walls================= // 未实现 非空 null null // 已实现 null null // 正在实现 null 这个

此补丁也修复了 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)`可以重新出现这个问题




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