Каква е ползата от екземпляра на монадата на Cont?

Играя си с CPS и Control.Monad.Cont и се чудя какво печелим, като забележим монадичната структура. За код като този:

sumOfSquares'cps :: Cont r Int -> Cont r Int -> Cont r Int
sumOfSquares'cps x y = x >>= \x' ->
                       y >>= \y' ->
                       return (x'*x' + y'*y')

Може лесно да се пренапише като

type Cont' r a = (a -> r) -> r

sos'cps :: Cont' r Int -> Cont' r Int -> Cont' r Int
sos'cps x y = \k -> x $ \x' -> 
                    y $ \y' -> 
                    k (x'*x' + y'*y') 

Не ме разбирайте погрешно, но не виждам усещането тук, освен че мога да използвам нотация do и newtype. Не мисля, че callCC също зависи от екземпляра на монадата.

Липсва ми въображение, за да измисля пример. Какво всъщност получаваме, като обявим Cont r за монада?


person Sebastian Graf    schedule 10.06.2014    source източник
comment
Не мисля, че callCC също зависи от екземпляра на монадата. Строго погледнато, нищо никога не е. Например в Maybe монадата return = Just и (=<<) = maybe Nothing. Класът Monad абстрахира вече съществуваща функционалност, за да направи възможни нещата, които Майкъл Снойман споменава в своя отговор.   -  person duplode    schedule 10.06.2014
comment
Има смисъл, след като помислих. Въпреки че обикновено, когато видя преработени функции, използващи bind, получавам приятно топло усещане в стомаха си, което ми казва, че съм постъпил правилно. Не го разбирам за Cont, защото предполагам, че няма реална разлика в синтаксиса.   -  person Sebastian Graf    schedule 10.06.2014
comment
За да разберете защо синтактичната захар изглежда толкова тънка за Cont, може да искате да проверите Майката на всички монади.   -  person Ørjan Johansen    schedule 13.06.2014


Отговори (2)


Можете да зададете същия въпрос на всеки Monad. На пръв поглед мога да се сетя за три предимства:

  1. Получавате достъп до огромната колекция от функции, които са проектирани да работят с Monads.
  2. Можете да използвате do-нотация.
  3. Можете да подреждате монадни трансформатори, за да създадете нещо по-мощно.

Това също ви позволява да разсъждавате по-добре за вашия код, тъй като можете да разчитате на идентичност и асоциативни свойства и други подобни.

person Michael Snoyman    schedule 10.06.2014
comment
Това са нещата, които изникнаха в главата ми веднага след публикуването на въпроса :). Предполагам, че бях разочарован от почти идентичния синтаксис, където операторите за свързване в други монади правят кода някак чист. Това е наивно, защото монадите служат за различна цел от подобряването на синтаксиса. - person Sebastian Graf; 10.06.2014

Едно очевидно предимство е, че можете да използвате комбинаторите, дефинирани за MonadsFunctors). Например, вашата функция може да бъде написана с помощта на liftM2:

sumOfSquares'cps :: Cont r Int -> Cont r Int -> Cont r Int
sumOfSquares'cps = liftM2 sumSquares
  where sumSquares x y = x * x + y * y

тази функция не разчита на това, че монадата е Cont и може да бъде написана с по-общ тип, напр.

sumOfSquaresM :: Monad m => m Int -> m Int -> m Int
person Lee    schedule 10.06.2014