2012-08-05 9 views
9

Versuchen, Ocamls Mechanismus für benannte Parameter zu verstehen. Ich verstehe die Grundlagen, aber die doc zeigt ein Beispiel wie folgt aus:Ocamls benannte Parameter

# let f ~x ~y = x - y;; 
val f : x:int -> y:int -> int = <fun> 

# let x = 3 and y = 2 in f ~x ~y;; 
- : int = 1 

Was genau los ist, wenn nur die Tilde in der Anwendung verwendet wird? Ist es nur eine Abkürzung für ~x:x, Definitionen ähnlich? Wenn ja, kann mir jemand erklären, warum dies:

# ListLabels.fold_left;; 
- : f:('a -> 'b -> 'a) -> init:'a -> 'b list -> 'a = <fun> 

# let add = (+) and i = 0 
in ListLabels.fold_left ~add ~i [1;2;3];; 

produziert
- : f:((add:(int -> int -> int) -> i:int -> 'a) -> 
    int -> add:(int -> int -> int) -> i:int -> 'a) -> 
init:(add:(int -> int -> int) -> i:int -> 'a) -> 'a = <fun> 

Antwort

8

Der Mann sagt „Vorsicht, dass Funktionen wie ListLabels.fold_left deren Ergebnistyp ist, wird eine Variable vom Typ nie als völlig angewendet betrachtet werden . "

Hier ist, was in Ihrem Beispiel passiert. Vorsicht, es ist ein bisschen beteiligt.

# ListLabels.fold_left;; 
- : f:('a -> 'b -> 'a) -> init:'a -> 'b list -> 'a = <fun> 

ist nur die klassische Verwendung: ListLabels.fold_left taks 3 Argumente, nämlich eine Funktion f, eine initializer init und eine Liste markiert. Jetzt

, in

let add = (+) and i = 0 
in ListLabels.fold_left ~add ~i [1;2;3];; 

die Anwendung ListLabels.fold_left ~add ~i [1;2;3] gilt als unvollständig (wie der Mann sagt). Das bedeutet, dass `ListLabels.fold_left zuerst das ungedammte Argument [1;2;3] empfängt und eine Funktion vom Typ f:('a -> int -> 'a) -> init:'a -> 'a zurückgibt. Nennen wir diese Funktion foo.

Da Sie zwei benannte Argumente geben, etikettiert add und i, die Art 'a wird gefolgert, ein Funktionstyp zu sein, vom Typ add:'c -> ~i:'d -> 'e.

Basierend auf der Art des Variablenadd und i, der Typ 'c muss int -> int -> int sein und 'd muss int sein.

Ersetzen diese Werte in der Art 'a, leiten wir, dass der Typ 'aadd:(int -> int -> int) -> i:int -> 'e ist. Und dies in der Art von foo ersetzen (ich bin froh, dass es kopier Einfügen ;-), seine Art

f:((add:(int -> int -> int) -> i:int -> 'e) 
    -> int 
    -> (add:(int -> int -> int) -> i:int -> 'e)) 
-> init:(add:(int -> int -> int) -> i:int -> 'e) 
-> (add:(int -> int -> int) -> i:int -> 'e) 

Entfernen unecessary Klammern ist, und Alpha-Umwandlung (dh Umbenennung) 'e-'a, erhalten wir

f:((add:(int -> int -> int) -> i:int -> 'a) 
    -> int 
    -> add:(int -> int -> int) -> i:int -> 'a) 
-> init:(add:(int -> int -> int) -> i:int -> 'a) 
-> add:(int -> int -> int) -> i:int -> 'a 

das ist die Art von foo ist. Aber denken Sie daran, dass Sie zwei Argumente an foo übergeben, die mit ~add und ~i gekennzeichnet sind. Der Wert, den Sie am Ende erhalten, ist nicht vom Typ add:(int -> int -> int) -> i:int -> 'a, sondern vom Typ 'a. Und die ganze Art von Ihrem Beispiel ist, wie durch den Compiler zurückgegeben,

f:((add:(int -> int -> int) -> i:int -> 'a) 
    -> int 
    -> add:(int -> int -> int) -> i:int -> 'a) 
-> init:(add:(int -> int -> int) -> i:int -> 'a) 
-> 'a 
+0

Wow - was für ein Durcheinander! Es macht aber tatsächlich Sinn, vielen Dank! – scry

+0

Gern geschehen, es war auch schön zu lösen ;-) – jrouquie

Verwandte Themen