Что я могу сделать с callCC, что нельзя сделать с помощью cont? - PullRequest
7 голосов
/ 06 ноября 2019

Я действительно очень стараюсь понять callCC. Я получаю силу от Continuations и использую концепцию в некоторых своих проектах для создания классных концепций. Но мне никогда не приходилось использовать что-то с более широкими возможностями, чем cont :: ((a->r)->r)-> Cont r a.

. После его использования становится понятным, почему они называют Cont Monad матерью всех монад, ДА, я неполучить, когда мне нужно будет использовать callCC, и это точно мой вопрос.

1 Ответ

8 голосов
/ 06 ноября 2019

callCC дает вам семантику «раннего возврата», но в монадическом контексте.

Скажем, вы хотите doOne, и если это возвращает True, вы немедленно останавливаетесь, иначе вы продолжаетедо doTwo и 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

Видите, что if разветвляется там? Одна ветвь не так уж и плоха, с ней можно иметь дело, но представьте, что есть несколько таких точек, где вы просто хотите получить залог? Это очень уродливо и очень быстро.

С callCC вы можете получить «ранний возврат»: вы делаете залог в точке ветвления и не должны вкладывать остальные вычисления:

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

Гораздо приятнее читать!

Что еще более важно, поскольку ret здесь не является специальным синтаксисом (например, return в C-подобных языках), а просто значением, аналогичным любому другому, вы можетепередать его и другим функциям! И эти функции могут затем выполнять то, что называется «нелокальным возвратом» - то есть они могут «останавливать» вычисления doThings, даже от нескольких вложенных глубоких вызовов. Например, я мог бы выделить проверку результата doOne в отдельную функцию checkOne, например:

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

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