Що я можу зробити з callCC, що неможливо зробити з продовженням?


9

Я справді дуже боюся з розумінням callCC. Я отримую силу продовжень і використовую цю концепцію в деяких своїх проектах, щоб створити круті концепції. Але ніколи мені не потрібно було використовувати щось з більшими можливостями, ніж cont :: ((a->r)->r)-> Cont r a.

Після його використання має багато сенсу, чому вони називають Cont Monad матір'ю всіх монад, та все ж я не розумію, коли б мені потрібно було користуватися callCC, і це саме моє питання.


Як ти користувався Cont? Коли ви говорите, що вам не потрібно було використовувати щось більш потужне, ніж contце означає, що ви цього не використовували resetчи те чи інше shift?
К. А. Бур

Я не використовував resetабо shift. Я використовував його для визначення вбудованої мови, яку можна призупинити, поки певна дія не буде вирішена іншим процесом, а потім вона відновиться із заданим "продовженням". Можливо, у мене склалося враження, що я маю багато досвіду з Cont Monad, але це не так вже й дуже, я просто хочу зрозуміти callCC
Алехандро Навас

Відповіді:


10

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у мовах подібних С), а просто значення, як і будь-яке інше, ви можете передавати його і іншим функціям! І ці функції можуть виконувати те, що називається "нелокальним поверненням" - тобто вони можуть "зупинити" doThingsобчислення, навіть від декількох вкладених дзвінків у глибину. Наприклад, я міг би визначити перевірку doOneрезультату на окрему функцію, checkOneяк це:

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

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

Я розумію! і bв основному є простою карткою, щоб ви могли продовжувати більше продовжень всередині callCC. У будь-якому разі, як тільки retбуде застосовано, продовження, створене за допомогою виклику cc, "поверне" все, що було додано ret. Це досить заплутано, але досить розумно, але надзвичайно потужно, я бачу не так багато місць, де користуватися такою силою не так, як вбивати муху
Алехандро Навас

1
@caeus Радий, що можу допомогти. Якщо вам сподобалась моя відповідь, ви могли б прийняти її?
Федір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.