男人說 「提防功能,如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