Ocaml的命名参数

scr*_*cry 9 ocaml currying named-parameters

试图了解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
Run Code Online (Sandbox Code Playgroud)

在应用中仅使用波浪号时究竟发生了什么?它只是简写~x:x,类似于定义吗?如果是这样,有人可以解释为什么这样:

# 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];;
Run Code Online (Sandbox Code Playgroud)

产生

- : 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>
Run Code Online (Sandbox Code Playgroud)

jro*_*uie 9

该男子说"请注意像ListLabels.fold_left这样的函数,其结果类型是一个类型变量,永远不会被视为完全应用."

以下是您的示例中发生的情况.要小心它有点牵扯.

# ListLabels.fold_left;;
- : f:('a -> 'b -> 'a) -> init:'a -> 'b list -> 'a = <fun>
Run Code Online (Sandbox Code Playgroud)

只是经典用法:接受ListLabels.fold_left3个参数,即标记的函数f,初始值设定项init和列表.

现在,在

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

该申请ListLabels.fold_left ~add ~i [1;2;3]被认为是不完整的(如该男子所说).这意味着`ListLabels.fold_left首先接收其未命名的参数,[1;2;3]并返回类型的函数f:('a -> int -> 'a) -> init:'a -> 'a.让我们称这个函数为foo.

既然你给了两个命名参数,标记addi,类型'a推断是一个功能型的类型,add:'c -> ~i:'d -> 'e.

基于该类型的变量 addi,类型'c必须是int -> int -> int,而且'd必须是int.

替换类型中的那些值'a,我们得出类型'aadd:(int -> int -> int) -> i:int -> 'e.并在foo类型中替换它(我很高兴有复制粘贴;-),它的类型是

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)
Run Code Online (Sandbox Code Playgroud)

删除不必要的括号,和α转换(即重命名)'e'a,我们得到

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
Run Code Online (Sandbox Code Playgroud)

这就是foo的类型.但请记住,你将两个参数传递给foo,标记为~add~i.所以你在最后得到的价值不是类型,add:(int -> int -> int) -> i:int -> 'a而是类型'a.您的示例的整个类型是由编译器返回的,

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
Run Code Online (Sandbox Code Playgroud)