2011-01-13 7 views
71

Mehrere Parameterlisten, z.B. def foo(a:Int)(b:Int) = {} und mehrere Parameter pro Liste, z.B. def foo(a:Int, b:Int) = {} sind semantisch gleichwertig, soweit ich das beurteilen kann, und die meisten funktionalen Sprachen haben nur eine Möglichkeit, mehrere Parameter zu deklarieren, z. F #.Warum bietet Scala sowohl mehrere Parameterlisten als auch mehrere Parameter pro Liste?

Der einzige Grund, warum ich beide Stile von Funktionsdefinitionen unterstützen kann, ist syntaxähnliche Spracherweiterungen mit einer Parameterliste, die nur einen Parameter enthält.

def withBufferedWriter(file: File)(block: BufferedWriter => Unit) 

kann nun mit der Syntax-Suche

withBufferedWriter(new File("myfile.txt")) { out => 
    out write "whatever" 
    ... 
} 

jedoch genannt werden, könnte es andere Möglichkeiten, die Verwendung von geschweiften Klammern unterstützen, ohne dass mehrere Parameterlisten zu haben.

Eine verwandte Frage: Warum wird die Verwendung von mehreren Parameterlisten in Scala "currying" genannt? Gewöhnlich wird Currying als eine Technik definiert, um eine n-ary-Funktion zum Unterstützen einer teilweisen Anwendung unförmig zu machen. In Scala kann man jedoch teilweise eine Funktion anwenden, ohne eine "curried" Version (mehrere Parameterlisten mit jeweils einem Parameter) der Funktion zu erstellen.

+0

Allgemein gilt: es ist einfach mathematisch ausdrucksstark.Warum reicht es mit einer Liste, wenn Sie auf eine Mehrzahl verallgemeinern können? – matanster

Antwort

75

Es macht Dich in der Lage zB zu tun:

scala> def foo(as: Int*)(bs: Int*)(cs: Int*) = as.sum * bs.sum * cs.sum 
foo: (as: Int*)(bs: Int*)(cs: Int*)Int 

scala> foo(1, 2, 3)(4, 5, 6, 7, 9)(10, 11) 
res7: Int = 3906 
+2

Eine Einschränkung davon ist, dass, obwohl Sie für jede Parametergruppe eine variable Länge haben, die Anzahl der Gruppen fest sein muss (in diesem Fall bei 3). –

+25

Da Sie diese Antwort akzeptiert haben, sollte angemerkt werden, dass dies nur ein Beispiel ist und möglicherweise nicht die kanonische Antwort auf Ihre Frage "Warum" ist. –

+1

Dies ist der erste konkrete Grund, den ich bisher für beide Arten von Parametern gesehen habe. Alle anderen sind ziemlich ad hoc. Nichtsdestoweniger sehe ich keinen dieser Gründe, die das syntaktische Gepäck und die Komplikation der Sprache wert sind. –

23

Sie zu beantworten, „damit verbundene Frage,“ currying ist einfach eine Möglichkeit, eine Funktion von mehreren Argumenten Drehen, zum Beispiel (A, B, C) => D, in eine Funktion, die man braucht Argument und gibt eine Funktion, z A => (B => (C => D)) (Klammern sind gezeigt, aber nicht notwendig).

Die tupelisierte Form und die Curryform sind isomorph, und wir können zwischen ihnen frei übersetzen. All dies sind gleichwertig, haben aber unterschiedliche syntaktische Implikationen:

(A, B, C, D, E) => F 
((A, B), (C, D, E)) => F 
(A, B) => (C, D, E) => F 

Wenn Sie separate Parametergruppen erklären, dies ist die Art von currying ist Sie tun. Das Multi-Parameter-Gruppe ist ein Verfahren, das eine Funktion gibt ... Sie dies in der REPL zu sehen:

scala> def foo(a:Int, b:Int)(c:Int, d:Int, e:Int):Int = 9 
foo: (a: Int,b: Int)(c: Int,d: Int,e: Int)Int 

scala> foo _            
res4: (Int, Int) => (Int, Int, Int) => Int = <function2> 
43

Neben dem Sie Methoden zu schreiben, wie ein Teil der Sprache aussehen (die Sie bereits entdeckt), es ist erwähnenswert, dass der Typ-Inferenzrechner mit jeweils einem Block arbeitet.

So in dieser:

def foo[T](a: T, b: T)(op: (T,T)=>T) = op(a,b) 
foo(1,2){_+_} 

T wird zunächst als Int abgeleitet werden, die dann als Typ der zwei Unterstrichen im Verschluss verwendet werden. So weiß der Compiler bei vollständiger Typsicherheit, dass die Operation + gültig ist.

12

Ich weiß, eine der Motivationen war implizite Parameterlisten. "implizit" ist eine Eigenschaft der Liste, nicht der Parameter. Eine andere war wahrscheinlich Fallklassen: Nur die erste Parameterliste wird zu Fallfeldern.

+0

Interessant. Gibt es eine Chance, dass du das weiter ausbauen kannst? –

+1

Sieht wie keine Chance aus ... – zapadlo

+0

In Fallklassen mit mehreren Parameterlisten, siehe [Kommentare zu diesem Fehler] (https://issues.scala-lang.org/browse/SI-5009). Da habe ich zuerst von diesem Feature gehört. – ebruchez

18

Zurück Referenzen in Standardargumente:

case class Foo(bar: Int) 

def test(f: Foo)(i: Int = f.bar) = i*i 

test(Foo(3))()