2013-04-18 14 views
6

Ich versuche zu verstehen, was Typ-Annotationen im Zusammenhang mit Funktionen höherer Ordnung bedeuten. Hier ein Beispiel:Wie funktionieren Namen-Name-Argumente in Funktionen höherer Ordnung?

object Test { 
    def apply[A, B](f: (=> A) => B, x: => A): B = f(x) 
    def const[A](ignored: A): Int = 1 
    val res: Int = apply(const, ???) 
} 

const ist streng in ihrem Argument (das heißt eine => Anmerkung fehlt), also warum ist es nicht ihr Argument zu zwingen (die ??? ist in diesem Fall) und löst eine Ausnahme?

Gibt es ein Papier, das hier die Semantik beschreibt?

Ich bin auf der Suche nach einer verbindlichen Antwort hier.

Antwort

5

Das Argument f in Ihrer apply Funktion ist eine Funcion1, die einen Parameter vom Typ eines BA und gibt Call-by-Namen nimmt. Daher wird f(x) den Aufruf-nach-Name-Parameter x nicht auswerten, aber seine Referenz direkt an f übergeben.

Es ist hilfreich, res zu verstehen, wie folgt:

def res[C]: Int = apply[C, Int](const, ???) 

wo in Ihrem Beispiel C ein unspezifischer Art sein würde. Was ist der Typparameter für const in dieser Zeile? Es ist => C. Leider kann man nicht, dass der Parameter eingeben:

def res[C]: Int = apply[C, Int](const[=> C], ???) // illegal syntax 

Aber können Sie überprüfen, was los ist:

def res[C]: Int = apply[C, Int](const[Nothing], ???) 

geben Sie

<console>:10: error: type mismatch; 
found : Nothing => Int 
required: => C => Int 
     def res[C]: Int = apply[C, Int](const[Nothing], ???) 
              ^

Diese Art erscheint innerhalb const als Function0[Int] (so Scala behandelt implizit Aufrufe von Namen oder "Thunk" -Argumente als eine Funktion ohne Argumente. Auch hier können Sie dies überprüfen:

def const[A](ignored: A): Int = if (ignored.isInstanceOf[Function0[_]]) 1 else 0 

Jetzt Test.res Sie 1 geben wird (was bedeutet, dass ignored ist in der Tat ein Function0).


So ist die Frage eine andere Art und Weise zu beantworten, hat const ein eifriges Argument vom Typ A, aber das tut hier keine Rolle, weil A eine Funktion in Ihrem Beispiel wird, und Sie nie diese Funktion anwenden, deshalb ??? wird nie ausgeführt.


Es ist some debate zu why there is both A "Thunk" oder Klammern lose Funktion und eine leere-paren Funktion (Function0) in Scala.

+0

Ich denke, das könnte auf http://scalapuzzlers.com/ – ghik

+0

Vielen Dank für die detaillierte Erklärung. Ist die Semantik des Bedarfs (die ich für meinen Namen hielt) in Scala irgendwo definiert? Typischerweise werden Strictness-Eigenschaften in Bezug auf die angewendete Funktion definiert (in diesem Fall "const"), aber Ihre Erklärung bezieht sich sehr stark auf die Implementierung und wie das Argument für "const" konstruiert wird. – tibbe

+0

Eine weitere Frage, kann ein Typparameter "A" sowohl mit einem by-value-Argument (z. B. "Int") als auch mit einem by-neft-Argument (d. H. "=> Int")? – tibbe

0

Ich öffne eine andere Antwort, weil es immer noch nicht klar, Sie scheint, was passiert:

Typischerweise Strikt Eigenschaften sind in Bezug auf die Funktion definiert (in diesem Fall const) angewendet wird, aber Ihre Erklärung ist, sehr viel über die Implementierung und wie das Argument zu const konstruiert wird.

ich Ihr Objekt mit unterschiedlichen Typennamen neu formulieren wird:

object Test { 
    def apply[A, B](f: (=> A) => B, x: => A): B = f(x) 
    def const[C](ignored: C): Int = 1 
    def res[A1]: Int = apply[A1, Int](const, ???) 
} 

Jetzt mit Function0 by-name Parameter, lassen Sie uns Austausch, wo die "Faulheit" markieren versteckt:

object Test { 
    def apply[A, B](f: (() => A) => B, x:() => A): B = f(x) 
    def const[C](ignored: C): Int = 1 
    def res[A1]: Int = apply[A1, Int](const[() => A1],() => ???) 
} 

Sie sehen, die Definition von const spielt keine Rolle. Was zählt, ist, dass das x Argument zu apply By-Name (oder eine Funktion in der letzten Version) ist. So ruft f(x)f mit ein Funktionsargumentx, so was auch immer x 's Körper ist, das wird an dieser Stelle nicht ausgewertet.

Verwandte Themen