【发布时间】:2021-07-16 05:00:57
【问题描述】:
作为 Scala 开发人员学习 IO Monad,因此一般来说 Trampolining 的技术对于无法进行尾调用优化的递归是必需的,我想知道 Haskell 似乎是如何在本机避免它的。
我知道 Haskell 是一种惰性语言,但我想知道是否有人可以进一步详细说明。
例如,为什么 ForeverM stackoverflow 不在 Scala 中?好吧,我可以回答蹦床,我可以在库和博客中找到执行此操作的实际代码。我实际上自己实现了一个基本的蹦床来学习。
它在 Haskell 中是如何发生的?有没有办法解开懒惰的包装,提供一些指示,也许还有有助于更好地理解它的文档?
sealed trait IO[A] {
.....
def flatMap[B](f: A => IO[B]): IO[B] =
FlatMap[A,B](this, f) // we do not interpret the `flatMap` here, just return it as a value
def map[B](f: A => B): IO[B] =
flatMap[B](f andThen (Return(_)))
}
case class Return[A](a: A) extends IO[A]
case class Suspend[A](resume: () => A) extends IO[A]
case class FlatMap[A,B](sub: IO[A], k: A => IO[B]) extends IO[B]
......
@annotation.tailrec
def run[A](io: IO[A]): A = io match {
case Return(a) => a
case Suspend(r) => r()
case FlatMap(x, f) => x match {
case Return(a) => run(f (a))
case Suspend(r) => run(f( r()))
case FlatMap(y, g) => run(y flatMap (a => g(a) flatMap f))
}
}
【问题讨论】:
-
“我们不在这里解释
flatMap,只是将它作为一个值返回”基本上是Haskell中发生的一直,没有明确说明 - 一切都只是一个懒惰的重击,它由一个执行整个程序的巨大蹦床评估。
标签: scala haskell recursion tail-recursion trampolines