2015-03-05 19 views
6

Ho imparato che Monad.Reader è in realtà un incapsulamento di una funzione, vale a dire:Qual è la differenza tra Monad.Reader e le (->) monadi?

newtype Reader r a = Reader { runReader :: r -> a } 

che è fatto un'istanza di Monade,

instance Monad (Reader r) where 
    return a = Reader $ \_ -> a 
    m >>= k = Reader $ \r -> runReader (k (runReader m r)) r 

Al contrario, sapevo che (->) è anche una Monade,

instance Monad ((->) r) where 
    return = const 
    f >>= k = \ r -> k (f r) r 

Dalle definizioni E 'in grado di vedere che in realtà si comportano allo stesso esattamente.

Così sono intercambiabili in tutti gli usi? E qual è il vero significato di differenziare queste due Monadi?

+0

possibile duplicato di [Esiste un modo "standard" per utilizzare l'equivalenza di Reader e una funzione normale?] (Http://stackoverflow.com/questions/28613651/is-there-any-standard-way-to -utilizzare-l'-equivalenza-di-lettore-e-un-normale-fu) –

+1

In breve, si tratta di essere in grado di usare 'do' notation e' >> = '. Puoi prendere un parametro nel contesto invece di passarlo esplicitamente: 'f >> = g >> = h' vs' f a. g a. h a'. I meccanismi sottostanti sono gli stessi. –

+2

Puoi anche usare notazione con il normale tipo di freccia sin dalla sua istanza di 'Monad' – user3585010

risposta

9

TL; DR

sono la stessa cosa.

Alcune lezioni di storia

State, Writer e Reader sono stati ispirati da Mark P. Jones' Functional Programming with Overloading and Higher-Order Polymorphism, dove ha definito Reader come segue:

Un Reader monade viene utilizzato per consentire un calcolo per l'accesso i valori contengono in alcuni ambienti chiusi (rappresentati dal tipo r nelle seguenti definizioni ).

> instance Monad (r->) where 
>  result x = \r -> x 
>  x `bind` f = \r -> f (x r) r 

Come commento di passaggio, è interessante notare che queste due funzioni sono solo le normali K e S combinatori della logica combinatoria.

In seguito, egli definisce (quasi) di oggi MonadReader:

Reader monads: Una classe di monadi per descrivere calcoli che consultare qualche ambiente fisso:

> class Monad m => ReaderMonad m r where 
>  env :: r -> m a -> m a 
>  getenv :: m r 

> instance ReaderMonad (r->) r where 
>  env e c = \_ -> c e 
>  getenv = id 

getenv è semplicemente ask e env è local . const. Pertanto, questa definizione conteneva già tutte le parti significative di un Reader. In definitiva, Jones definisce il trasformatore Monade ReaderT (BComp è composizione indietro):

Per cominciare, è utile definire due diverse forme di composizione; avanti (FComp) e all'indietro (BComp):

> data FComp m n a = FC (n (m a)) 
> data BComp m n a = BC (m (n a)) 

[omettendo Functor, Monade e outof istanze]

> type ReaderT r = BComp (r ->) 

Da StateT, WriterT, e altri avevano loro variante non trasformatore, esso era solo logico avere uno Reader r, che in realtà è lo stesso di (->) r.

ogni modo, oggi Reader, Writer e State sono definiti in termini di variante trasformatore, e si utilizza il loro rispettivo Monad* typeclass (MonadReader).

Conclusione

Quindi sono loro intercambiabili in tutti gli usi?

Sì.

E qual è il vero significato di differenziare queste due Monadi?

Nessuno, tranne che ReaderT è in realtà un trasformatore Monade, il che rende le cose più facili.

+0

Perché le mie risposte ultimamente si riferiscono a documenti o documenti di 20 anni o al nucleo di GCC/GHC? – Zeta

+0

Potresti aggiungere la definizione di 'BComp' per completezza? Immagino sia qualcosa di simile a 'newtype BComp f g x = BComp (g (f x))'? – dfeuer

0

Sono infatti esattamente gli stessi. Possiamo renderlo più formale mappando tra di loro: toArrow :: Reader r a -> r -> a e toReader :: (r -> a) -> Reader r a con implementazioni toReader = Reader e toArrow = runReader.

Modifica: La semantica dietro a Reader è che contiene una configurazione di sola lettura che è possibile eseguire il threading della catena di calcoli. Si dovrebbe sempre preferire un Reader usando il tipo di freccia semplice quando si desidera collegare alcune informazioni di configurazione, poiché fa parte di un'interfaccia molto generica che fornisce utili funzioni di supporto, una classe MonadReader per manipolare i tipi di dati Reader come pure un ReaderT per impilamento Monad s.

Problemi correlati