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中的此类示例)。

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

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

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

补丁后
|状态|f|sv|s|
| :-- | :-- | :-- | :-- | :-- |
|未实现|非空null|null|
|已实现|null|null|这个之外的所有东西|
|正在实现|null|null|这个|

0

评论者:jafingerhut

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

0

评论者:cgrand

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

// 在调用用户代码之前 (f.invoke() 在 sval 中,以及在间接的 ((LazySeq)ls).sval() 在 seq 中 --甚至在 seq 中的 RT.seq() 中),确保 LazySeq 的状态在这些状态之一:// // 状态 f sv // ================================ // 未实现 非空 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。它通过了测试,我没有看到任何问题,但最好 if 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 报告)
...