2016-11-06 3 views
6

Die Frage ist ausschließlich über Scala-Syntax, obwohl es etwas Code von akka (als Beispiel) enthält.Verständnis der Funktion in Scala

Ich bin ziemlich neu in Scala. Graben in den Quellcode von akka kam ich mit dem folgenden ziemlich seltsam Methode up:

def transform[C] 
(f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = 
Unmarshaller.withMaterializer { implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) } 

wo Unmarshaller.withMaterializer definiert als

def withMaterializer[A, B](f: ExecutionContext ⇒ Materializer => A ⇒ Future[B]): Unmarshaller[A, B] 

Was ist hier los? Was ist die gruselige Funktion f: ExecutionContext => Materializer => Future[B] => Future[C]. Und was mir merkwürdiger erschien, war die Sequenz implicit s: implicit ec => implicit mat => a => f(ec)(mat)(this(a)), obwohl withMaterializer keine impliziten Parameter hat.

Was bedeutet implizit in solchen Sequenzen?

Antwort

2

f: ExecutionContext => Materializer => Future[B] => Future[C] ist nichts anderes als eine curried Funktion, so dass Sie es wie f(ec)(mat)(this(a)) mit mehreren Parameter aufrufen Listen (naja, technisch Parameter Listen gehören nicht zu der gleichen Funktion im Gegensatz zu def f(...)(...), aber das sind Details). Mit anderen Worten f kann geschrieben werden:

f: ExecutionContext => { Materializer => { Future[B] => Future[C] } }` 

(Funktion, die eine Funktion gibt, die noch eine weitere Funktion gibt) Jetzt

wenn man sich f(ec)(mat)(this(a)) sehen gibt es einen Aufruf this(a), die gerade oben definiert ist transform:

def apply(value: A)(implicit ec: ExecutionContext, materializer: Materializer): Future[B] 

(this(a) ist einfach ein Aufruf an this.apply(a)). Jetzt apply hat zwei implizite Parameter, nämlich ec: ExecutionContext und materializer:Materializer, so wie es this(a) nennen Sie zwei implizite Werte benötigen. Was genau ist die Definition implicit ec ⇒ implicit mat ⇒ a ⇒ f(ec)(mat)(this(a)) bedeutet.Es erklärt ec und mat als implicits für alle geschachtelten Funktion Körper so this(a) kann sie abholen. Eine andere Möglichkeit wäre zu schreiben:

ec ⇒ mat ⇒ a ⇒ f(ec)(mat)(this(a)(ec, mat)) 
0

Es ist ein Lambda mit currying und impliziten Parametern (die im Rahmen der Deklaration sein sollen).

Die „scary“ Funktionstyp Syntax ist currying: eine Funktion von einem Argument, das ExecutionContext und gibt eine weitere Funktion von einem Argument, das Materializer und gibt eine andere Funktion übernimmt, ... usw. Eine andere Sache implicit arguments ist.

Hier ist ein einfacheres Beispiel für eine ähnliche Konstruktion:

implicit val implicitInt: Int = 5 
implicit val implicitString: String = "0" 

val f: Int => String => String = { 
    implicit a => { 
    implicit b => { 
     a.toString + b 
    } 
    } 
} 

Hier f ist eine Funktion, die curried Int und gibt eine Funktion, die String nimmt nimmt und String. Die allgemeine Syntax für eine Funktionswertdeklaration lautet val f = { argument => ... }. Wenn Sie dieses Argument implizit angeben, bedeutet dies, dass eine Instanz dieses Typs im Bereich vorhanden sein muss, die als Standard value fungiert. Sie können weiterhin f auf einige Argumente anwenden: f(1)(""), weil es immer noch eine Funktion ist.

Sie könnten den Code neu schreiben Sie viel mehr verbosely sind gefragt durch für jeden Schritt verschachtelte Funktionen definieren:

def transform[C](f: ExecutionContext ⇒ Materializer ⇒ Future[B] ⇒ Future[C]): Unmarshaller[A, C] = { 

    def getExecutionContext(implicit ec: ExecutionContext): Materializer => (A => Future[B]) = { 

    def getMaterializer(implicit mat: Materializer): A => Future[B] = { 

     def applyF(a: A): Future[B] = f(ec)(mat)(this(a)) 
     applyF // : A => Future[B] 
    } 

    getMaterializer // : Materializer => (A => Future[B]) 
    } 

    Unmarshaller.withMaterializer(
    getExecutionContext // : ExecutionContext => (Materializer => (A => Future[B])) 
) 
} 
+0

Ich glaube nicht, dass Sie Ihr 'f' ohne Parameter aufrufen können, um implizite Werte zu verwenden. Es funktioniert nur für Methoden. 'implizit' im Funktionsliteral bedeutet, dass das Argument im Funktionskörper implizit ist. –

+0

Sie haben Recht. 'f' ist nicht als Methode mit Standardparametern verwendbar. Ich habe versucht, diese Konstruktion mit einem einfacheren Beispiel zu illustrieren, habe sie aber aus dem Zusammenhang genommen. – laughedelic