Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么Scala book中FP的非蹦床IO monad实现会产生StackOverflowerr错误?_Scala_Functional Programming - Fatal编程技术网

为什么Scala book中FP的非蹦床IO monad实现会产生StackOverflowerr错误?

为什么Scala book中FP的非蹦床IO monad实现会产生StackOverflowerr错误?,scala,functional-programming,Scala,Functional Programming,我正在学习Scala书中的函数编程。在第13章。外部效应和I/O,第13.3点避免StackOverflower错误,第237页有一个例子,说明了通过本章开发的带有IO monad的简单程序如何引发StackOverflower错误 崩溃代码很简单: IO.forever(IO { println("Still going...") }).run 可以找到IO特征和同伴对象的源 我一眼就看不出为什么会抛出StackOverflowerError,所以我仔细研究了这个示例,展开并计算表达式,就像

我正在学习Scala书中的函数编程。在第13章。外部效应和I/O,第13.3点避免StackOverflower错误,第237页有一个例子,说明了通过本章开发的带有IO monad的简单程序如何引发
StackOverflower错误

崩溃代码很简单:

IO.forever(IO { println("Still going...") }).run
可以找到IO特征和同伴对象的源

我一眼就看不出为什么会抛出
StackOverflowerError
,所以我仔细研究了这个示例,展开并计算表达式,就像我是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
永远
的定义很简单:

def forever[A,B](a: F[A]): F[B] = {
  lazy val t: F[B] = a.flatMap(_ => t)
  t
}

我在纸笔评估中做错了什么?Scala是否在我的大脑Scala之前评估了
lazy val
t

我认为
lazy val
没有问题。相反,当从

(new IO[Unit] {
  def run = (_ => t)(self.run).run
}).run


实际上,它正在调用
self.run
,同时仍在外部
run
评估的上下文中-它尚未从
def run
返回
我认为
lazy val
没有问题。相反,当从

(new IO[Unit] {
  def run = (_ => t)(self.run).run
}).run


实际上,它正在调用
self.run
时,仍然在外部
run
计算的上下文中-它还没有从
def run
返回,您的意思是:
(new IO[Unit]{def run=(=>t)(self.run.run})。run
的计算结果是:
>“仍在运行…”/*from self.run*/(new IO)[Unit]{def run=t.run}).run
?在匿名IO trait实例的构造上是否对新IO[Unit]{def run=…}
进行了评估?是的。否。我不知道,根据第3.3.1节,这个术语重写似乎不适合表示任何地方的调用堆栈。方法类型:“一种特殊情况是没有任何参数的方法类型。它们在此处写入=>T。无参数方法名称表达式,每次引用无参数方法名称时都会重新计算。”。如果我没有弄错,则使用无参数方法(
new IO[Unit]{def run=…}
,在这种情况下)是的。首先它构造
IO[Unit]
实例,然后在其上调用无参数
run
方法。在
run
主体的求值过程中(即
run
仍在堆栈上),它将调用
self.run
,然后调用
t.run
才有意义。我在评估表达式时就好像它是Haskell一样,我忘记了JVM是基于堆栈的。我从Alvin Alexander的“函数编程,简化”中找到了一个很好的摘录,它解释了JVM调用堆栈对Scala函数的影响。你的意思是:
(新IO[Unit]{def run=(=>t)(self.run.run}).run
的计算结果为:
“仍在运行…”/*from self.run*/(新IO[Unit]{def run=t.run})。run
新IO[Unit]{def run=…}
对匿名IO trait实例的构造进行了评估?是的。不是。我不知道,根据第3.3.1节的方法类型,这个术语“重写”似乎不适合表示任何地方的调用堆栈:一种特殊情况是没有任何参数的方法类型。它们写在这里=>T。每次引用无参数方法名称时,都会重新计算无参数方法名称表达式。“。如果我没有弄错,则使用无参数方法(
new IO[Unit]{def run=…}
)是的。首先它构造
IO[Unit]
实例,然后在其上调用无参数
run
方法。在
run
主体的求值过程中(即
run
仍在堆栈上),它将调用
self.run
,然后调用
t.run
才有意义。我对表达式的评估就像它是Haskell一样,我忘记了JVM是基于堆栈的。我从Alvin Alexander的“函数编程,简化”中找到了一个很好的摘录,它解释了JVM调用堆栈对Scala函数的影响。