define
def memoizeCoeval(n: Int): Coeval[Int] = {
if (n <= 1)
Coeval.now(1)
else
Coeval.defer(memoizeCoeval(n - 1)).map(_ + 1).memoize
}
现在
memoizeCoeval(10000).value
吹堆栈。如果我们从递归调用中删除.memoize
,它会工作(如预期的那样(。为什么?
这是Coeval的缺点,你可以使用Eval代替它以相同的方式进行堆栈安全的递归记忆计算。
如果没有memoize
,你会得到一个由Suspend
s组成的Coeval。每个Suspend
都包含一个 thunk,它是一个返回下一个Suspend
的函数:运行循环通过在 thunk 上调用apply
,将生成的Coeval
设置为当前,然后继续循环来展开它。
当使用memoize
时,Suspend
包含一个扩展() -> Coveal
的LazyVal
。它以一种直接调用apply
自己的底层 thunk 的方式覆盖apply
,而 thunk 又调用运行循环。所以当LazyVal
的apply
在运行循环中被调用时,它会递归调用运行循环,这会导致堆栈溢出。
我不知道这是否是一个错误,因为Coeval
意味着堆栈安全,但请注意,记住递归方法的每个步骤是没有意义的,因为相应的 Coveal 永远不会被重用。您可能只想记住最终结果。