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

提案: 缓存在惰性序列实现中抛出的异常,以避免再次运行声明为 ^:once 的 bodyfn

预审: Alex Miller

4 答案

0

_评论由:find_myway

我可能应该使用 take-while 而不是 filter

然而,有人能解释为什么在第一次运行

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

时会得到 ArithmeticException,在第二次时却能得到正确的结果吗?

0

评论由:bronsa

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

惰性序列期望 bodyfn 只运行一次,然后将其结果缓存,但如果在执行 bodyfn 时抛出异常,则当序列再次尝试实现时,函数将再次运行。但是如果局部变量已被清理(即使部分清理了),这意味着 bodyfn 中的一些变量现在将是nil,而不是保持其实际值。

0

评论由:bronsa

附带的补丁已修复此问题

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