Que puis-je faire avec callCC qui ne peut pas être fait avec cont?

9

J'ai vraiment du mal à comprendre callCC. J'ai la puissance de Continuations et j'ai utilisé le concept dans certains de mes projets pour créer des concepts sympas. Mais je n'ai jamais eu besoin d'utiliser quelque chose avec de plus grandes capacités quecont :: ((a->r)->r)-> Cont r a .

Après l'avoir utilisé, il est très logique pourquoi ils appellent la Cont Monad la mère de toutes les monades, ENCORE, je ne sais pas quand devrais-je utiliser callCC, et c'est exactement ma question.

Alejandro Navas
la source
Comment l'avez-vous utilisé Cont? Lorsque vous dites que vous n'avez pas eu besoin d'utiliser quelque chose de plus puissant que cont, cela signifie-t-il que vous n'avez pas utilisé resetou shiftnon?
KA Buhr
Je n'ai pas utilisé resetou shift. Je l'ai utilisé pour définir un langage intégré qui peut être suspendu jusqu'à ce qu'une action donnée soit résolue par un autre processus, puis il reprend avec la "continuation" donnée. Peut-être que je donne l'impression d'avoir beaucoup d'expérience avec Cont Monad, mais pas vraiment, je veux vraiment comprendre callCC
Alejandro Navas

Réponses:

10

callCC vous donne une sémantique de "retour précoce", mais dans un contexte monadique.

Supposons que vous vouliez doOne, et si cela revient True, vous vous arrêtez immédiatement, sinon vous continuez doTwoet 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

Vous voyez cette ifbranche là-bas? Une branche n'est pas si mal, pourrait être traitée, mais imaginez qu'il y a plusieurs points de ce genre où vous voulez juste renflouer? Cela devient très moche très rapidement.

Avec callCCvous pouvez avoir un "retour anticipé": vous vous renflouez au point de branchement et n'avez pas à imbriquer le reste du calcul:

doThings = callCC \ret -> do
    one <- doOne
    when one $ ret ()
    doTwo
    doThree

Beaucoup plus agréable à lire!

Plus important encore, comme retil ne s'agit pas d'une syntaxe spéciale (comme returndans les langages de type C), mais simplement d'une valeur comme les autres, vous pouvez également la transmettre à d'autres fonctions! Et ces fonctions peuvent alors effectuer ce qu'on appelle un "retour non local" - c'est-à-dire qu'elles peuvent "arrêter" le doThingscalcul, même à partir de plusieurs appels imbriqués en profondeur. Par exemple, je pourrais factoriser la vérification du doOnerésultat dans une fonction distincte checkOnecomme celle-ci:

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

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree
Fyodor Soikin
la source
J'ai compris! et best fondamentalement juste un caractère générique afin que vous puissiez enchaîner plus de continuations dans callCC. Quoi qu'il en soit, une fois retappliquée, la suite produite par l'appel cc "retournera" tout ce qui a été mis ret. C'est assez compliqué, mais assez intelligent, mais extrêmement puissant, je ne vois pas beaucoup d'endroits où utiliser un tel pouvoir n'est pas comme tuer une mouche avec une bombe nucléaire
Alejandro Navas
1
@caeus Heureux d'avoir pu aider. Si vous avez aimé ma réponse, envisageriez-vous de l'accepter?
Fyodor Soikin