object test2 {
//a naive IO monad
sealed trait IO[A] { self =>
def run: A
def map[B](f: A => B): IO[B] = new IO[B] { def run = f(self.run) }
def flatMap[B](f: A => IO[B]): IO[B] = {
println("calling IO.flatMap")
new IO[B] {
def run = {
println("calling run from flatMap result")
f(self.run).run
}
}
}
}
object IO {
def unit[A](a: => A): IO[A] = new IO[A] { def run = a }
def apply[A](a: => A): IO[A] = unit(a) // syntax for IO { .. }
}
//composer in question
def forever[A,B](a: IO[A]): IO[B] = {
lazy val t: IO[B] = a flatMap (_ => t)
t
}
def PrintLine(msg: String) = IO { println(msg) }
def say = forever(PrintLine("Still Going..")).run
}
test2.say代码将堆栈溢出之前打印数千“仍在继续”。但我不知道到底发生了什么。
输出看起来是这样的:
斯卡拉> test2.say
调用IO.flatMap //只有一次
从flatMap结果调用运行
仍在继续..
从flatMap结果
调用运行 还在..
... //重复直到堆栈溢出
当乐趣ction 永远返回,是完全计算(缓存)的懒惰值? 而且,flatMap方法似乎只被调用一次(我添加了打印语句),这反映了永远的递归定义。为什么?
===========
我觉得有趣的另一件事是永远的B型可以是任何东西。实际上斯卡拉可以运行它不透明。
我手动尝试永远[单位,双],永远[单位,字符串]等,这一切工作。这感觉很聪明。
'IO'在哪里定义?请发布你的问题[MCVE]。 –
这是合理的 – user1206899