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