我真的很想了解callCC。我拥有Continuations的力量,并且在我的一些项目中一直在使用该概念来创建很酷的概念。但是我从来不需要使用功能比cont :: ((a->r)->r)-> Cont r a
强的东西。
使用它后,很有意义,为什么他们将Cont Monad称为所有Monad的母亲,是的,我不知道何时需要使用callCC
,这正是我的问题。
我真的很想了解callCC。我拥有Continuations的力量,并且在我的一些项目中一直在使用该概念来创建很酷的概念。但是我从来不需要使用功能比cont :: ((a->r)->r)-> Cont r a
强的东西。
使用它后,很有意义,为什么他们将Cont Monad称为所有Monad的母亲,是的,我不知道何时需要使用callCC
,这正是我的问题。
callCC
可让您“尽早返回”语义,但在单子语境中。
假设您要doOne
,如果返回True
,则立即停止,否则继续进行doTwo
和doThree
:
doOne :: Cont r Bool
doTwo :: Cont r ()
doThree :: Cont r ()
doThings :: Cont r ()
doThings = do
one <- doOne
if one
then pure ()
else do
doTwo
doThree
看到if
在那里分支了吗?一个分支不是那么糟糕,可以解决,但是想象一下,您想保释的地方有多个?这变得非常丑陋。
使用callCC
,您可以“提前返回”:您在分支点保释,而不必嵌套其余的计算:
doThings = callCC \ret -> do
one <- doOne
when one $ ret ()
doTwo
doThree
阅读起来更加愉快!
更重要的是,由于ret
并不是一种特殊的语法(类似于C语言中的return
),而只是一个值,因此您也可以将其传递给其他函数!然后这些函数可以执行所谓的“非本地返回”-即,即使从多个嵌套调用开始,它们也可以“停止” doThings
计算。例如,我可以将对doOne
结果的检查排除在一个单独的函数checkOne
中,如下所示:
checkOne ret = do
one <- doOne
when one $ ret ()
doThings = callCC \ret -> do
checkOne ret
doTwo
doThree