男人说 “提防功能,如ListLabels.fold_left,其结果类型是一个类型变量将永远不会被视为完全适用“。
以下是您的示例中会发生的情况。请注意这有点牵扯。
# ListLabels.fold_left;;
- : f:('a -> 'b -> 'a) -> init:'a -> 'b list -> 'a = <fun>
就是经典的使用:ListLabels.fold_left
TAKS 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)
删除不必要的括号,和α转换(即重命名)'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
哇 - 多么混乱!它确实是有道理的,非常感谢你! – scry 2012-08-06 07:58:50
不客气,它也很好解决;-) – jrouquie 2012-08-06 14:16:36