Ocaml的命名参数

时间:2012-08-05 23:45:57

标签: ocaml currying named-parameters

尝试理解Ocaml的命名参数机制。我理解基础知识,但doc显示了这样的示例:

# 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

在应用程序中仅使用波浪号时究竟发生了什么?它只是~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];;

产生

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

1 个答案:

答案 0 :(得分:8)

男人说 “请注意,ListLabels.fold_left等结果类型为类型变量的函数永远不会被视为完全应用。”

以下是您的示例中发生的情况。请注意它有点牵扯。

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

只是经典用法:ListLabels.fold_left包含3个参数,即标记为f的函数,初始值设定项init和列表。

现在,在

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

应用程序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)

删除不必要的括号,并将alpha转换(即重命名)'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

这就是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