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)
该男子说"请注意像ListLabels.fold_left这样的函数,其结果类型是一个类型变量,永远不会被视为完全应用."
以下是您的示例中发生的情况.要小心它有点牵扯.
# ListLabels.fold_left;;
- : f:('a -> 'b -> 'a) -> init:'a -> 'b list -> 'a = <fun>
Run Code Online (Sandbox Code Playgroud)
只是经典用法:接受ListLabels.fold_left
3个参数,即标记的函数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.
既然你给了两个命名参数,标记add
和i
,类型'a
推断是一个功能型的类型,add:'c -> ~i:'d -> 'e
.
基于该类型的变量 add
和i
,类型'c
必须是int -> int -> int
,而且'd
必须是int
.
替换类型中的那些值'a
,我们得出类型'a
是add:(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)