2015-03-05 11 views
6

ich gelernt, dass Monad.Reader tatsächlich eine Kapselung einer Funktion, nämlich:Was ist der Unterschied zwischen Monad.Reader und den (->) Monaden?

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

die eine Instanz von Monad gemacht wird,

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

Im Gegensatz wusste ich, dass (->) ist auch ein Monad,

Von den Definitionen ist es in der Lage zu sehen, dass sie sich tatsächlich genau gleich verhalten.

So sind sie in allen Verwendungen austauschbar? Und was ist die tatsächliche Bedeutung der Unterschiede zwischen diesen beiden Monaden?

+0

mögliche Duplikate von [Gibt es einen "Standard" Weg, die Äquivalenz von Reader und einer normalen Funktion zu nutzen?] (Http://stackoverflow.com/questions/28613651/is-there-any-standard-way-to -utilize-the-equivalent-of-reader-and-a-normal-fu) –

+1

Kurz gesagt, es geht darum, 'do' Notation und' >> = 'zu verwenden. Sie können einen Parameter in den Kontext bringen, anstatt ihn explizit zu übergeben: 'f >> = g >> = h 'vs' f a. g a. h a'. Die zugrunde liegende Mechanik ist dieselbe. –

+2

Sie können Do-Notation auch mit dem normalen Pfeiltyp verwenden, da die Instanz von 'Monad' – user3585010

Antwort

9

TL; DR

Sie sind gleich.

Einige Geschichtsunterricht

State, Writer und Reader wurden inspiriert von Mark P. Jones' Functional Programming with Overloading and Higher-Order Polymorphism, wo er Reader wie folgt definiert:

A Reader Monade verwendet wird, eine Berechnung für den Zugriff zu ermöglichen, Die Werte wurden in einigen umschließenden Umgebung gehalten (dargestellt durch den Typ r in den folgenden Definitionen).

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

als vorübergehender Kommentar, ist es interessant, dass diese beiden Funktionen nur die Standard-K und S combinators kombinatorischer Logik sind zu beachten.

Später legt er (fast) der heutigen MonadReader:

Reader monads: Eine Klasse von Monaden für Berechnungen beschreiben, die einige feste Umgebung konsultieren:

> 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 einfach ist ask und env ist local . const. Daher enthielt diese Definition bereits alle wesentlichen Teile eines Reader. Letztlich definiert Jones den monadisch Transformator ReaderT (BComp ist rückwärts Zusammensetzung):

Um damit zu beginnen, ist es nützlich, zwei verschiedene Formen der Zusammensetzung zu definieren; vorwärts (FComp) und nach hinten (BComp):

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

> type ReaderT r = BComp (r ->) 

Da StateT, WriterT, und andere hatten ihre nicht-Transformator Variante [Functor, Monad und OUTOF Instanzen Weglassen] Es war nur logisch, ein Reader r, das ist wirklich das gleiche wie (->) r.

So oder so, heute Reader, Writer und State sind hinsichtlich ihrer Transformatorvariante definiert, und Sie verwenden, um ihre jeweiligen Monad* typeclass (MonadReader).

Fazit

So sind sie in allen Verwendungen austauschbar?

Ja.

Und was ist die tatsächliche Bedeutung der Unterscheidung dieser beiden Monaden?

Keine, außer die ReaderT tatsächlich eine Monade Transformator ist, die Dinge einfacher macht.

+0

zu finden Warum gehen meine Antworten in letzter Zeit in ~ 20 Jahre alte Papiere oder Dokumente oder in den Kern von GCC/GHC? – Zeta

+0

Könnten Sie die Definition von 'BComp' der Vollständigkeit hinzufügen? Ich stelle mir vor es ist so etwas wie 'newtype BComp f gx = BComp (g (fx))' '? – dfeuer

0

Sie sind in der Tat das gleiche. Wir können dies formeller machen durch Zuordnung zwischen ihnen: toArrow :: Reader r a -> r -> a und toReader :: (r -> a) -> Reader r a mit Implementierungen toReader = Reader und toArrow = runReader.

Edit: Die semantische hinter einem Reader ist, dass es einige schreibgeschützte Konfiguration enthält, die Sie durch Ihre Kette von Berechnungen führen können. Sie sollten immer eine Reader über die Verwendung der einfachen Pfeil-Typ bevorzugen, wenn Sie einige Konfigurationsinformationen thread, weil es Teil einer sehr allgemeinen Schnittstelle, die nützliche Hilfsfunktionen, eine MonadReader Klasse für die Manipulation von Reader wie Datentypen sowie eine ReaderT zum Stapeln Monad s.

Verwandte Themen