Cosa posso fare con callCC che non può essere fatto con cont?


9

Sono davvero alle prese con la comprensione di callCC. Ottengo il potere di Continuations e ho usato il concetto in alcuni dei miei progetti per creare concetti interessanti. Ma non ho mai avuto bisogno di usare qualcosa con capacità maggiori di cont :: ((a->r)->r)-> Cont r a.

Dopo averlo usato, ha molto senso il motivo per cui chiamano Cont Monad la madre di tutte le monadi, ANCORA, non capisco quando dovrei usare callCC, ed è esattamente la mia domanda.


Come hai usato Cont? Quando dici che non hai bisogno di usare qualcosa di più potente di cont, significa che non hai usato reseto shiftneanche?
KA Buhr,

Non ho usato reseto shift. L'ho usato per definire un linguaggio incorporato che può essere sospeso fino a quando una determinata azione non viene risolta da un altro processo, e poi riprende con la "continuazione" data. Forse ho l'impressione di avere molta esperienza con Cont Monad, ma non molto, voglio solo capire callCC
Alejandro Navas,

Risposte:


10

callCC ti dà la semantica del "ritorno anticipato", ma in un contesto monadico.

Di 'che volevi doOne, e se questo ritorna True, ti fermi immediatamente, altrimenti vai avanti doTwoe 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

Vedi quella iframificazione lì? Un ramo non è poi così male, potrebbe essere affrontato, ma immagini ci sono più di questi punti in cui vuoi solo salvare? Questo diventa molto brutto molto rapidamente.

Con callCCte puoi avere un "ritorno anticipato": salvi al punto di diramazione e non devi nidificare il resto del calcolo:

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

Molto più piacevole da leggere!

Ancora più importante, dal momento che retqui non c'è una sintassi speciale (come returnnei linguaggi simili a C), ma solo un valore come un altro, puoi passarlo anche ad altre funzioni! E queste funzioni possono quindi eseguire ciò che viene chiamato "ritorno non locale", ovvero possono "interrompere" il doThingscalcolo, anche da più chiamate nidificate in profondità. Ad esempio, potrei scomporre il controllo del doOnerisultato in una funzione separata checkOnecome questa:

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

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

Capisco! ed bè fondamentalmente solo un jolly in modo da poter concatenare più continuazioni all'interno di callCC. Ad ogni modo, una volta retapplicato, la continuazione prodotta dalla chiamata cc "restituirà" qualunque cosa sia stata inserita ret. È piuttosto contorto, ma piuttosto intelligente, ma estremamente potente, non vedo molti posti in cui usare un tale potere non è come uccidere una mosca con una bomba atomica
Alejandro Navas,

1
@caeus Sono contento di poterti aiutare. Se ti è piaciuta la mia risposta, valuteresti di accettarla?
Fyodor Soikin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.