2016-03-28 6 views
0

Ich bin ein Scala-Neuling. Ich komme aus einem Java-Hintergrund. Ich habe Monaden gelesen und eine allgemeine Vorstellung davon entwickelt. Während ich die map und flatMap Operationen auf Typen wie List zu schätzen weiß, kann ich meinen Kopf nicht einwickeln, was sie bedeuten, wenn es reader monad s kommt. Könnte jemand bitte ein paar einfache Beispiele dafür aufstellen.Was bedeutet die Karte und flache Karte Operationen für einen ReaderMonad

Ich verstehe, wir brauchen ReaderMonads, um unäre Funktionszusammensetzung zu erleichtern, so dass wir fancy Syntax wie for - consrefions verwenden können. Ich verstehe auch, dass wir die Götter der Monade zufrieden stellen müssen, damit dies geschieht. Alles, was ich verstehen will, ist "Was bedeutet Map und Flatmap" für Funktionen?

Antwort

4

Die Reader-Monade, oft geschrieben Reader[A, B], ist nur der Funktionstyp A => B. Eine Codierung von Monaden in Scala wie folgt aussieht:

trait Monad[M[_]] { 
    def pure[A](a: A): M[A] 
    def flatMap[A, B](ma: M[A])(f: A => M[B]): M[B] 
} 

wo map können in Bezug auf pure und flatMap wie so umgesetzt werden:

def map[A, B](ma: M[A])(f: A => B): M[B] = flatMap(ma)(a => pure(f(a))) 

Also erste, was wir tun müssen, ist unsere Binärart zu machen Konstruktor Reader passt in den unären Typkonstruktor, den Monad erwartet. Dies geschieht, indem der erste (Eingabe-) Typ-Parameter festgelegt und der zweite (Ausgabe-) Typ-Parameter freigelassen wird.

implicit def readerMonad[X]: Monad[X => ?] = ??? 

(Die Verwendung von ? hier ist über die wunderbare kind-projector Compiler Plugin).

Beginnend mit pure ersetzen wir das Auftreten von M[_] durch X => _.

def pure[A](a: A): X => A 

einen Wert vom Typ Gegeben A, müssen wir eine Funktion zurück, die einen Wert vom Typ X gegeben, gibt einen Wert vom Typ A. Das einzige, was dies möglicherweise sein kann, ist die konstante Funktion.

def pure[A](a: A): X => A = _ => a 

Jetzt flatMap ..

def flatMap[A, B](ma: X => A)(f: A => (X => B)): X => B = (x: X) => ??? 

Dies ist ein bisschen schwierig ersetzen, aber wir können Arten nutzen, um uns auf die Umsetzung zu führen! Wir haben:

ma: X => A 
f: A => (X => B) 
x: X 

Und wir wollen eine B bekommen. Die einzige Möglichkeit, das zu tun, ist über f, die eine A und eine X will. Wir haben genau eine X von x, aber wir brauchen eine A. Wir sehen, wir können nur eine A von ma bekommen, die eine X, die uns nur x bietet uns wünscht. Deshalb haben wir ..

def flatMap[A, B](ma: X => A)(f: A => (X => B)): X => B = 
    (x: X) => { 
    val a = ma(x) 
    val b = f(a)(x) 
    b 
    } 

laut lesen, flatMap auf Reader sagt einen Wert A aus der "Umwelt" (oder "config") X zu lesen.Verzweigen Sie dann auf A, lesen Sie einen anderen Wert B aus der Umgebung.

Wir gehen weiter und implementieren map auch manuell:

def map[A, B](ma: X => A)(f: A => B): X => B = ??? 

an den Argumenten der Suche X => A und A => B, mit dem erwarteten Ausgang X => B, das genau wie Funktion Zusammensetzung aussieht, die in der Tat ist es.

Beispiel der Verwendung cats mit Importen mit:

import cats.data.Reader 

Angenommen, wir haben einige Config Typ:

case class Config(inDev: Boolean, devValue: Int, liveValue: Int) 

, die uns sagt, ob wir in einem „dev“ Umwelt sind und gibt wir Werte für etwas für "dev" und für "live". Wir können anfangen, indem wir eine einfache Reader[Config, Boolean] schreiben, die die inDev Flagge für uns vorliest.

Und wir können eine Plain-Funktion schreiben, die bei einigen Booleschen Werten den entsprechenden Wert anzeigt.

def branch(flag: Boolean): Reader[Config, Int] = 
    if (flag) Reader((c: Config) => c.devValue) 
    else  Reader((c: Config) => c.liveValue) 

Jetzt können wir bilden die beiden:

val getValue: Reader[Config, Int] = 
    for { 
    flag <- inDev 
    value <- branch(flag) 
    } yield value 

Und jetzt können wir unsere Int erhalten, indem in verschiedenen Config Werte übergeben:

getValue.run(Config(true, 1, 2)) // 1 
getValue.run(Config(false, 1, 2)) // 2 

Dies kann im Allgemeinen als eine verwendet werden netter Weg, um Abhängigkeitsinjektion zu erreichen, mit nur Funktionen!

+0

Thx für die Antwort. Sehr tief. Ich muss das mehrmals lesen und sehen, ob ich es vollständig verstehe. Können Sie mir auch ein paar einfache Anwendungsbeispiele geben? –

+0

Ich habe meine Antwort so bearbeitet, dass sie ein Beispiel enthält :-) – adelbertc