要理解 callCC 在 Haskell 中的含义,您可能想查看它的类型,而不是它的实现:
callCC :: MonadCont m => ((a -> m b) -> m a) -> m a
这里第一个也是最重要的是 MonadCont m。这意味着 callCC 只能在实现 MonadCont 的 monad 中工作——这可能会让您失望,但 IO 不是 MonadCont 的实例。在这方面,callCC 并不像在方案中那样工作。
无论如何,callCC 的参数是((a -> m b) -> m a)
:这是一个计算,需要(a -> m b)
as its参数,这是 callCC 正在捕获的延续。那么让我们尝试编写一些使用 callCC 的东西:
import Control.Monad.Cont
fun _ = return "hi"
main = print $ runCont (callCC fun) id
现在这非常无聊,因为我们不以任何方式使用延续。让我们尝试一下不同的乐趣:
fun' escape = do escape "ahoy"
return "die die die"
当您运行代码时,您将看到转义的“调用”永远不会“返回”——它调用了延续,就像在方案中一样。你可能知道“返回”在 Haskell 中不是这样工作的:它不是一个短路操作。您可以认为 callCC 为您提供了一种提前终止计算的方法。
在实现级别上, cont 和 runCont 是与延续传递风格相互转换的函数。您将需要更详细地研究延续单子以了解它的实际工作原理。尝试例如。http://www.haskellforall.com/2012/12/the-continuation-monad.html
(在许多方案实现中,call/cc 也不能真正通过“保存调用堆栈”来工作。如果将程序转换为 CPS,call/cc 就不再是“免费”的东西了。我想你可能会想要阅读例如这个http://www.pipeline.com/~hbaker1/CheneyMTA.html,其中讨论了一种在低级别实施 CPS 的方法。)