2012-08-05 18 views
9

Cố gắng hiểu cơ chế của Ocaml cho các tham số được đặt tên. Tôi hiểu những điều cơ bản, nhưng doc thấy một ví dụ như thế này:Các thông số có tên của Ocaml

# 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 

Chính xác những gì đang xảy ra khi chỉ có các dấu ngã được sử dụng trong ứng dụng? Nó chỉ là viết tắt của ~x:x, tương tự như định nghĩa? Nếu vậy, ai đó có thể giải thích tại sao điều này:

# 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];; 

sản xuất

- : 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> 

Trả lời

8

Người đàn ông nói "hãy cẩn thận rằng các chức năng như ListLabels.fold_left có loại kết quả là một loại biến sẽ không bao giờ được coi là hoàn toàn áp dụng . "

Đây là những gì xảy ra trong ví dụ của bạn. Hãy coi chừng đó là một chút liên quan.

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

chỉ là việc sử dụng cổ điển: ListLabels.fold_left taks 3 đối số, cụ thể là một chức năng được dán nhãn f, một initializer init và một danh sách.

Bây giờ, trong

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

ứng dụng ListLabels.fold_left ~add ~i [1;2;3] được coi là không đầy đủ (tùy theo từng người đàn ông nói). Điều đó có nghĩa là `ListLabels.fold_left nhận được đối số chưa được đặt tên đầu tiên của nó, [1;2;3] và trả về một chức năng loại f:('a -> int -> 'a) -> init:'a -> 'a. Chúng ta hãy gọi hàm này là foo.

Vì bạn đang đem lại cho hai tên đối số, dán nhãn addi, loại 'a được suy ra là một loại chức năng, kiểu add:'c -> ~i:'d -> 'e.

Dựa vào loại của biếnaddi, loại 'c phải int -> int -> int, và 'd phải int.

Thay thế các giá trị đó trong loại 'a, chúng tôi lấy được rằng loại 'aadd:(int -> int -> int) -> i:int -> 'e. Và thay thế này trong các loại foo (Tôi rất vui vì có sao chép dán ;-), kiểu của nó là

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) 

Loại bỏ ngoặc hưởng ứng nhiệt liệt, và alpha chuyển đổi (tức là đổi tên) 'e-'a, chúng tôi nhận

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 

Đó là loại foo. Nhưng hãy nhớ rằng bạn đang chuyển hai đối số cho foo, được gắn nhãn ~add~i. Vì vậy, giá trị bạn nhận được ở cuối không phải là loại add:(int -> int -> int) -> i:int -> 'a nhưng thực sự thuộc loại 'a. Và toàn bộ loại ví dụ của bạn là, được trả về bởi trình biên dịch,

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 - thật là lộn xộn! Nó thực sự có ý nghĩa mặc dù, cảm ơn bạn rất nhiều! – scry

+0

Bạn được chào đón, nó là tốt đẹp để giải quyết quá ;-) – jrouquie