我正在阅读Scala中的函数式编程一书。在第13章外部效果和I / O,第13.3节避免StackOverflowError,第237页中,有一个示例说明了通过本章开发的带有IO monad的简单程序如何激发StackOverflowError
。
崩溃的代码很简单:
IO.forever(IO { println("Still going...") }).run
可以找到IO特征和伴随对象的来源here
我乍看之下为什么抛出StackOverflowError
,所以我通过示例,扩展和评估表达式,就好像我是Scala运行时一样。经过一些迭代后,我回到起点(t.run
)。我无法达到在调用堆栈上多次调用run
的情况:
IO.forever(IO { println("Still going...") }).run
t.run
(a.flatMap(_ => t)).run
(new IO[Unit] {
def run = (_ => t)(self.run).run
}).run
(_ => t)(self.run).run
> "Still going..."
(_ => t)(()).run
t.run
forever
的定义很简单:
def forever[A,B](a: F[A]): F[B] = {
lazy val t: F[B] = a.flatMap(_ => t)
t
}
我的铅笔和纸张评估中我做错了什么? Scala是否在之前评估 my-brain-Scala 的lazy val
t
?
答案 0 :(得分:2)
我认为lazy val
存在问题。相反,您只是在从
(new IO[Unit] {
def run = (_ => t)(self.run).run
}).run
到
(_ => t)(self.run).run
虽然实际上它仍然在外部self.run
评估的上下文中调用run
,但它尚未从def run
返回。