为了上下文,该问题是在 Slack 上的 https://clojurians.slack.com/archives/C03S1L9DN/p1650480331191719 上开始的。
此代码在 CLJ 上运行正常,但在 CLJS 上会抛出StackOverflowError
。
(def primes (remove
(fn [x]
(some #(zero? (mod x %)) primes))
(iterate inc 2)))
在此情况下,CLJ 和 CLJS 之间的关键区别在于,前者中 lazy-seq
实际上将其整个主体包装在一个带有 ^:once
的函数中。
之所以这样做的原因是在上面的代码中,内部的 primes
是一个闭包值,它成为一个局部变量。当 lazy-seq
的主体函数(带有 ^:once
)被第两次调用时,其局部变量是 nil
,因此内部 primes
也是 nil
。然后迭代停止。
在 CLJS 中,没有 :once
也没有局部变量清除,因此内部 primes
从不为 nil
,并且执行会继续进入该 fn
而不调用那个 zero?
。
即使这种推理听起来不太合理,但关于正是 :once
导致差异的假设可以很容易地通过在 CLJ 中不使用 :once
实现 lazy-seq
并注意到它会导致 StackOverflowError
来证实。
我不知道在这种情况下该怎么办,但或许至少应该在 https://script.clojure.org/about/differences 页面上增加一条注释。