O que posso fazer com callCC que não pode ser feito com cont?

9

Estou realmente lutando para entender o callCC. Eu tenho o poder das continuações e tenho usado o conceito em alguns dos meus projetos para criar conceitos interessantes. Mas nunca precisei usar algo com mais recursos do que cont :: ((a->r)->r)-> Cont r a.

Depois de usá-lo, faz muito sentido porque eles chamam a Cont Monad de mãe de todas as mônadas. AINDA, eu não entendo quando precisaria usá-la callCC, e essa é exatamente a minha pergunta.

Alejandro Navas
fonte
Como você usou Cont? Quando você diz que não precisou usar algo mais poderoso do contque isso significa que você não usou resetou shifttambém?
KA Buhr
Eu não usei resetou shift. Usei-o para definir uma linguagem incorporada que pode ser suspensa até que uma determinada ação seja resolvida por outro processo e, em seguida, continue com a "continuação" especificada. Talvez eu dar a impressão de ter um monte de experiência com Cont Mônada, mas não muito realmente, eu realmente quero entender callCC
Alejandro Navas

Respostas:

10

callCC fornece a semântica de "retorno antecipado", mas em um contexto monádico.

Digamos que você queira doOne, e se isso retornar True, você imediatamente para, caso contrário, prossegue 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

Vê aquela iframificação aí? Um ramo não é tão ruim assim, poderia ser tratado, mas imagine que há vários desses pontos em que você apenas quer fiança? Isso fica muito feio muito rapidamente.

Com callCCvocê pode ter "retorno antecipado": você paga no ponto de ramificação e não precisa aninhar o restante do cálculo:

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

Muito mais agradável de ler!

Mais importante, como retaqui não há uma sintaxe especial (como returnnas linguagens C), mas apenas um valor como qualquer outro, você também pode passá-lo para outras funções! E essas funções podem executar o que é chamado de "retorno não local" - ou seja, elas podem "parar" o doThingscálculo, mesmo a partir de várias chamadas aninhadas em profundidade. Por exemplo, eu poderia fatorar a verificação do doOneresultado de uma função separada checkOnecomo esta:

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

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree
Fyodor Soikin
fonte
Entendi! e bé basicamente apenas um curinga para que você possa encadear mais continuações no callCC. De qualquer forma, uma vez retaplicada, a continuação produzida pela chamada cc "retornará" tudo o que foi inserido ret. Isso é muito complicado, mas muito inteligente, mas extremamente poderoso eu não ver um monte de lugares onde o uso de tal poder não é como matar uma mosca com uma arma nuclear
Alejandro Navas
11
@caeus Ainda bem que pude ajudar. Se você gostou da minha resposta, consideraria aceitá-la?
Fyodor Soikin 7/11/19