2012-10-26 41 views
7

Ho difficoltà a capire come una funzione può essere una monade.Funzione come istanza di Monad

Funzione (->) r è una monade in base ad una dichiarazione in Control.Monad.Instances:

instance Monad ((->) r) where 
    return x = \_ -> x 
    h >>= f = \w -> f (h w) w 

Anche ciò che Miran Lipovača says su di esso mi rende confuso:

L'implementazione per >>= sembra un po 'criptico, ma in realtà non è lo . Quando si utilizza >>= per inviare un valore monadico a una funzione, il risultato è sempre un valore monadico. Quindi, in questo caso, quando alimentiamo una funzione in un'altra funzione, il risultato è anche una funzione. Questo è perché il risultato inizia come un lambda. Tutte le implementazioni di >>= finora hanno sempre in qualche modo isolato il risultato del valore monadico e quindi hanno applicato la funzione f a quel risultato. La stessa cosa succede qui. Per ottenere il risultato da una funzione, dobbiamo applicarlo a qualcosa, motivo per cui facciamo (h w) qui per ottenere il risultato dalla funzione e quindi applichiamo f a quello. f restituisce un valore monadico, che nel nostro caso è , quindi lo applichiamo anche a w.

Il tipo di firma (>> =) è questa: (>> =) :: ma -> (A -> mb) -> mb

così prendo che h viene digitato come m a e f come (a -> m b). Se una funzione è m a, restituisce un valore di tipo a? o restituisce qualcos'altro prendendo un tipo a?

Se il valore non-monade di h è alimentato a f, allora otteniamo: f (h w) guarda bene. Dal momento che f è una funzione e ha preso la sua unica argomentazione, è già un valore, no? Poiché si tratta di una funzione monadica, il valore è anche un valore monadico. Perché allora ha bisogno di un altro valore w? Non sta alimentando w a f something rendendolo non-monadico, cioè, non è più una funzione, no? Non riesco nemmeno a capire perché f something e h prendiamo lo stesso argomento w e restituiamo diversi tipi di valore (m a e m b).

risposta

10

In primo luogo, ecco il tipo di (>>=):

(>>=) :: (Monad m) => m a -> (a -> m b) -> m b 

Ora, con m specializzato per ((->) r):

(>>=) :: ((->) r) a -> (a -> ((->) r) b) -> ((->) r) b 

Riscritto con tutte le frecce funzione infisso:

(>>=) :: (r -> a) -> (a -> (r -> b)) -> (r -> b) 

Rimozione alcune parentesi superflue:

(>>=) :: (r -> a) -> (a -> r -> b) -> r -> b 

A tal punto che dovrebbe essere molto più facile vedere cosa sta succedendo: il terzo argomento (di tipo r) è dato al primo argomento per ottenere qualcosa di tipo a, allora sia che risultano e il terzo argomento vengono assegnati al secondo argomento per ottenere un risultato finale di tipo b.

Quindi, ((->) r) come Monad rappresenta un argomento di funzione aggiuntivo per ogni valore in quella monade e quando i valori monadici vengono combinati il ​​singolo argomento "extra" viene duplicato e assegnato a ciascun valore di input. In sostanza, questo crea un "ambiente globale di sola lettura" per i valori monadici. Questa interpretazione viene fornita esplicitamente come monad Reader, che è solo un wrapper attorno a ((->) r).

+0

Grazie. È tutto chiaro! – amemus

5

E 'forse più facile capire questo monade, cercando in ciò che join fa, dal momento che una monade può equivalentemente essere definita usando fmap e join invece di >>=.

Il formato generale di join ha il tipo Monad m => m (m b) -> m b, quindi richiede un valore monadico "a due livelli" e lo riduce a un livello.

Con la funzione monade m ~ (a ->), così join ha il tipo (a -> a -> b) -> (a -> b) così prende una funzione di due argomenti e restituisce una funzione che richiede un solo.

join :: (a -> a -> b) -> (a -> b) 
join f = \x -> f x x 

Come si può vedere, è solo duplica l'argomento.

Analogamente, fmap sulle funzioni è solo la composizione di funzione e return è const.

Penso che sia molto più facile capire in questo modo che cercare di dare un senso a >>=.

+0

Mentre ciò è utile per comprendere concettualmente l'istanza, è necessario ancora capire il comportamento di '>> =' per trovare cosa significa ogni riga nella notazione 'do' per quella monade. –

+0

@DanBurton: In questo caso penso che l'istanza 'Applicativa' sia la più semplice da spiegare e comprendere perché l''ambiente' è sempre il primo argomento, e l'istanza 'Monad' è equivalente all'ordine dei parametri. –