Was kann ich mit callCC tun, was mit cont nicht möglich ist?

9

Ich habe wirklich große Probleme damit, callCC zu verstehen. Ich bekomme die Kraft von Fortsetzungen und habe das Konzept in einigen meiner Projekte verwendet, um coole Konzepte zu erstellen. Aber ich musste nie etwas mit größeren Fähigkeiten als verwenden cont :: ((a->r)->r)-> Cont r a.

Nachdem ich es benutzt habe, ist es sehr sinnvoll, warum sie die Cont-Monade die Mutter aller Monaden nennen. NOCH, ich verstehe nicht, wann ich sie brauchen würde callCC, und genau das ist meine Frage.

Alejandro Navas
quelle
Wie hast du benutzt Cont? Wenn Sie sagen, dass Sie nichts Stärkeres als benötigen cont, bedeutet das, dass Sie es nicht verwendet haben resetoder auch shiftnicht?
KA Buhr
Ich habe nicht benutzt resetoder shift. Ich habe es verwendet, um eine eingebettete Sprache zu definieren, die angehalten werden kann, bis eine bestimmte Aktion durch einen anderen Prozess aufgelöst wird, und dann mit der angegebenen "Fortsetzung" fortgesetzt wird. Vielleicht habe ich den Eindruck, viel Erfahrung mit Cont Monad zu haben, aber nicht so viel, ich möchte callCC
Alejandro Navas

Antworten:

10

callCC gibt Ihnen "Early Return" -Semantik, aber in einem monadischen Kontext.

Angenommen , Sie wollten doOne, und wenn das zurückkehrt True, erhalten Sie sofort stoppen, sonst Sie gehen auf doTwound 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

Sehen Sie diese ifVerzweigung dort? Ein Zweig ist nicht so schlecht, könnte behandelt werden, aber stellen Sie sich vor, es gibt mehrere solcher Punkte, an denen Sie nur auf Kaution gehen möchten? Das wird sehr schnell sehr hässlich.

Mit können callCCSie "vorzeitige Rückkehr" haben: Sie kassieren am Verzweigungspunkt und müssen den Rest der Berechnung nicht verschachteln:

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

Viel angenehmer zu lesen!

Noch wichtiger ist, da es sich rethier nicht um eine spezielle Syntax (wie returnin C-ähnlichen Sprachen) handelt, sondern nur um einen Wert wie jeden anderen, können Sie ihn auch an andere Funktionen übergeben! Und diese Funktionen können dann eine sogenannte "nicht-lokale Rückgabe" ausführen - dh sie können die doThingsBerechnung "stoppen" , selbst wenn mehrere verschachtelte Aufrufe tief sind. Zum Beispiel könnte ich die Überprüfung des doOneErgebnisses in eine separate Funktion checkOnewie diese zerlegen:

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

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree
Fjodor Soikin
quelle
Ich verstehe es! und bist im Grunde nur ein Platzhalter, damit Sie mehr Fortsetzungen innerhalb von callCC verketten können. Sobald retes angewendet wird, wird die von call cc erzeugte Fortsetzung jedenfalls "zurückgeben", was auch immer eingegeben wurde ret. Das ist ziemlich verworren, aber ziemlich klug und doch extrem mächtig. Ich sehe nicht viele Orte, an denen es nicht so ist, eine Fliege mit einer Nuklearwaffe zu töten
Alejandro Navas
1
@ Caeus Ich bin froh, dass ich helfen konnte. Wenn Ihnen meine Antwort gefallen hat, würden Sie in Betracht ziehen, sie zu akzeptieren?
Fjodor Soikin