用cont无法完成的callCC我该怎么办?


9

我真的很难理解callCC。我拥有Continuations的力量,并且在我的一些项目中一直在使用该概念来创建很酷的概念。但是我从来没有必要使用功能比cont :: ((a->r)->r)-> Cont r a

在使用它之后,很有意义,为什么他们将Cont Monad称为所有Monad的母亲,是的,我不知道何时需要使用callCC,这正是我的问题。


你怎么用的Cont?当你说你有没有需要使用的东西比功能更强大cont,这是否意味着你没有使用resetshift要么?
KA Buhr

我没有使用过resetshift。我用它来定义一种嵌入式语言,可以将其挂起,直到给定的动作被另一个进程解决为止,然后以给定的“继续”继续进行。也许我给人留下了在Cont Monad方面有很多经验的印象,但实际上并没有那么多,我只是真的想了解callCC
Alejandro Navas

Answers:


10

callCC 给您“尽早返回”的语义,但在单子上下文中。

假设你想doOne,如果这回报True,你立刻停止,否则你去到doTwodoThree

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这里不是一种特殊的语法(像returnC语言一样),而只是一个值,因此您也可以将其传递给其他函数!然后,这些函数可以执行所谓的“非本地返回”-即doThings,即使从多个嵌套调用中进行深度调用,它们也可以“停止” 计算。例如,我可以将对doOne结果的检查排除在一个单独的函数中,checkOne如下所示:

checkOne ret = do
    one <- doOne
    when one $ ret ()

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree

我知道了!并且b基本上是一个通配符,这样你可以连里面callCC更多的延续。无论如何,一旦ret应用,调用cc产生的延续将“返回”任何放入的内容ret。那真是令人费解,却很聪明,但功能却非常强大。我看到在很多地方,使用这种力量并不像用核武器杀死苍蝇
Alejandro Navas

1
@caeus很高兴我可以提供帮助。如果您喜欢我的答案,您会考虑接受吗?
Fyodor Soikin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.