请在2024年 Clojure 状态调查中分享您的看法!

欢迎!有关如何运行的更多信息,请参阅关于页面。

0
Clojure

下面代码在 1.8.0 和 1.9.0-alpha14 版本中无法编译,两个版本中出现了相同的错误。

`
user=> (def fibonacci-1
((fn fib [a b]

(lazy-seq  (cons a  (fib b  (+ a b)))))
0 1))

user=> (filter #(< % 100) fibonacci-1)

ArithmeticException 整数溢出 clojure.lang.Numbers.throwIntOverflow (Numbers.java:1501)

user=> (filter #(< % 100) fibonacci-1)

NullPointerException clojure.lang.Numbers.ops (Numbers.java:1013)

user=> (def fibonacci-2

     (lazy-cat [0 1] (map + (rest fibonacci-2) fibonacci-2)))

user=> (filter #(< % 100) fibonacci-2)

ArithmeticException 整数溢出 clojure.lang.Numbers.throwIntOverflow (Numbers.java:1501)

user=> (filter #(< % 100) fibonacci-2)
(0 1 1 2 3 5 8 13 21 34 55 89)
`

补丁: 0001-CLJ-2069-cache-exceptions-thrown-during-lazy-seq-rea.patch

提案: 缓存 lazy-seq 实现期间抛出的异常,以避免重新运行声明为 ^:once 的 bodyfn

已预审: Alex Miller

4 个答案

0

_评论者:find_myway

也许我应该使用 take-while 而不是 filter

但是,有人能解释为什么我在第一次运行

(filter #(< % 100) fibonacci-2)

时会得到 ArithmeticException 而在第二次运行时得到正确的结果吗?

0

评论者:bronsa

NPE 是由以下因素相互作用的
- 懒序列在实现序列的一部分时抛出异常
- 懒序列内部使用 ^:once 来清除局部变量

lazy-seq期望bodyfn只被执行一次,然后将结果缓存起来,但如果在执行bodyfn的过程中抛出异常,当序列第二次尝试实现时该函数将再次被执行。然而,如果已经发生了局部变量的清除(即使部分清除),这意味着在bodyfn中的一些局部变量现在将是nil而不是保持它们的实际值。

0
by

评论者:bronsa

附上修复此问题的补丁

0
by
参考:[https://clojure.atlassian.net/browse/CLJ-2069](https://clojure.atlassian.net/browse/CLJ-2069)(由alex+import报告)
...