男人说
“请注意,结果类型为类型变量的 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。
由于您要给出两个命名参数,标记为 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)
删除不必要的括号,并将 alpha 转换(即重命名)'e 到 'a,我们得到 p>
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