Co mogę zrobić z callCC, czego nie można zrobić z cd?

9

Naprawdę mam problemy ze zrozumieniem callCC. Dostaję moc kontynuacji i wykorzystałem tę koncepcję w niektórych moich projektach, aby stworzyć fajne koncepcje. Ale nigdy nie musiałem używać czegoś o większych możliwościach niż cont :: ((a->r)->r)-> Cont r a.

Po użyciu ma sens, dlaczego nazywają Cont Monad matką wszystkich monad, JESZCZE, nie rozumiem, kiedy powinienem użyć callCC, i to jest dokładnie moje pytanie.

Alejandro Navas
źródło
Jak korzystałeś Cont? Kiedy mówisz, że nie musiałeś używać czegoś mocniejszego niż cont, czy to oznacza, że ​​nie używałeś resetczy shiftteż?
KA Buhr
Nie korzystałem resetlub shift. Użyłem go do zdefiniowania osadzonego języka, który można zawiesić, dopóki dana akcja nie zostanie rozwiązana przez inny proces, a następnie zostanie wznowiona z podaną „kontynuacją”. Może mam wrażenie, że mam duże doświadczenie z Cont Monad, ale nie bardzo, naprawdę chcę po prostu zrozumieć callCC
Alejandro Navas

Odpowiedzi:

10

callCC daje semantykę „wczesnego powrotu”, ale w kontekście monadycznym.

Powiedz, że chciałeś doOne, a jeśli to powróci True, natychmiast przerwiesz, w przeciwnym razie przejdziesz do doTwoi 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

Widzisz iftam rozgałęzienie? Jedna gałąź nie jest taka zła, można sobie z nią poradzić, ale wyobraź sobie, że istnieje wiele takich punktów, w których po prostu chcesz zwolnić za kaucją? To staje się bardzo brzydkie bardzo szybko.

Dzięki callCCmożesz mieć „wczesny powrót”: płacisz za kaucją w punkcie rozgałęzienia i nie musisz zagnieżdżać reszty obliczeń:

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

O wiele przyjemniej czytać!

Co ważniejsze, ponieważ rettutaj nie ma specjalnej składni (jak returnw językach podobnych do C), ale tylko wartość jak każda inna, możesz przekazać ją również do innych funkcji! Funkcje te mogą następnie wykonać tak zwany „powrót nielokalny” - tzn. Mogą „zatrzymać” doThingsobliczenia, nawet z wielu zagnieżdżonych wywołań głęboko. Na przykład, mogę doOneoddzielić sprawdzanie wyniku do oddzielnej funkcji, checkOnetakiej jak ta:

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

doThings = callCC \ret -> do
    checkOne ret
    doTwo
    doThree
Fiodor Soikin
źródło
Rozumiem! i bjest w zasadzie tylko symbolem wieloznacznym, dzięki czemu możesz połączyć więcej kontynuacji w callCC. W każdym razie po retzastosowaniu kontynuacja wywołana przez wywołanie cc „zwróci” wszystko, co zostało wprowadzone ret. To dość skomplikowane, ale całkiem sprytne, a jednocześnie niezwykle potężne. Nie widzę wielu miejsc, w których użycie takiej mocy nie jest jak zabicie muchy za pomocą broni nuklearnej
Alejandro Navas
1
@caeus Cieszę się, że mogłem pomóc. Jeśli podobała ci się moja odpowiedź, czy mógłbyś ją zaakceptować?
Fiodor Soikin,