2014-06-10 10 views
7

Sto giocando con CPS e Control.Monad.Cont e mi chiedo cosa guadagniamo notando la struttura monadica. Per il codice come questo:A che serve l'istanza monad di 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') 

possono facilmente essere riscritta come

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') 

Non fraintendetemi, ma non riesco a vedere la sensazione qui oltre ad essere in grado di utilizzare do notazione e un newtype. Non penso che callCC dipenda dall'istanza monad.

Mi manca l'immaginazione per fare un esempio. Cosa otteniamo in realtà per dichiarare una monade Cont r?

+3

"Non penso che' callCC' dipenda dall'istanza monad ". A rigor di termini, nulla lo è mai. Ad esempio, nel 'Maybe' monad' return = Just' e '(= <<) = forse Nothing'. La classe 'Monad' astra di funzionalità preesistenti per rendere le cose che Michael Snoyman accenna nella sua risposta possibile. – duplode

+0

Ha senso, dopo averci pensato. Anche se normalmente quando vedo le funzioni refactored usando il binding, ottengo una sensazione calda e accogliente nello stomaco che mi dice che ho fatto la cosa giusta. Non capisco per 'Cont', perché non c'è alcuna differenza reale nella sintassi, immagino. –

+1

Per capire perché lo zucchero sintattico sembra così particolarmente sottile per 'Cont', potresti voler controllare [La madre di tutte le monadi] (http://blog.sigfpe.com/2008/12/mother-of-all- monads.html). –

risposta

9

Si potrebbe fare la stessa domanda di qualsiasiMonad. Fuori della parte superiore della mia testa, mi viene in mente tre vantaggi:

  1. Si ottiene l'accesso alla vasta collezione di funzioni che sono progettati per lavorare con Monad s.
  2. È possibile utilizzare do -notazione.
  3. È possibile impilare i trasformatori monad per creare qualcosa di più potente.

Ciò consente anche di ragionare meglio sul codice, poiché è possibile fare affidamento su identità e proprietà associative e simili.

+1

Queste sono le cose che mi sono venute in mente subito dopo aver postato la domanda :). Immagino di essere stato deluso dalla sintassi quasi identica in cui gli operatori di bind di altre monadi rendono il codice un po 'pulito. È ingenuo, perché le monadi hanno uno scopo diverso dall'aumentare la sintassi. –

6

Un ovvio vantaggio è che è possibile utilizzare i combinatori definiti per Monads (e Functors). Ad esempio, la funzione potrebbe essere scritta utilizzando liftM2:

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

questa funzione non si basa sulla monade essere Cont e potrebbe essere scritta con un tipo più generale per esempio

sumOfSquaresM :: Monad m => m Int -> m Int -> m Int