关于上下文,最初在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
,执行会继续进入那个函数,甚至不调用那个zero?
。
即使这个理由听起来不太合理,但关于确实是因为:once
导致差异的假设可以通过在CLJ中实现不带:once
的lazy-seq
来轻松证实,并且会导致StackOverflowError
。
我不确定在这种情况下应该怎么做,但也许至少应该在此页面上注释放置一条注释。