2014-02-10 86 views
3

我有兩個功能:這兩個函數有什麼區別?

let rev_flatten l = 
    List.fold_left (fun acc x -> List.fold_left (fun acc y -> y::acc) acc x) [] l 

類型是val rev_flatten : 'a list list -> 'a list = <fun>

let rev_flatten = 
    List.fold_left (fun acc x -> List.fold_left (fun acc y -> y::acc) acc x) [] 

類型是val rev_flatten : '_a list list -> '_a list = <fun>


我認爲這是相同的功能,在至少相同的功能爲什麼他們有兩種不同的類型?爲什麼第二個元素的類型爲_a?它是什麼?

回答

4

以下劃線作爲前綴的類型變量告訴我們該變量是弱多態性。弱多態變量只能用於一種類型,但編譯器無法推導出確切的類型,因此類型變量帶有下劃線標記。

當您第一次提供參數時,變量將不再是多態,並且將只能接受單一類型的參數。

通常情況下,函數不是泛化的,但如果它的可能包含可變狀態,則標記爲弱多態。在你的例子中,這可能是這種情況,因爲類型系統不知道List.fold_left是純粹還是不純的函數。

編輯: 爲什麼避免局部應用(ETA膨脹)允許函數(偶數不純)是多態性?

讓我們定義一個函數,每次函數調用時都會增加一個內部計數器並將其打印出來。在這一點,它需要一個函數作爲參數,增加後的反抽應用它:

let count f = 
    let inc = ref 0 in 
    (fun x -> inc := !inc + 1; print_int !inc; f x);; 

此功能是多態的:('a -> 'b) -> 'a -> 'b

接下來,讓我們再定義兩個函數。理財一週報多態:

let max' = count max;; 
val max' : '_a -> '_a -> '_a = <fun> 

和多態之一:

let max'' x = count max x;; 
val max'' : 'a -> 'a -> 'a = <fun> 

現在請注意打印什麼,當我們執行這些功能:

max' 1 2;; (* prints 1 *) 
max' 1 2;; (* prints 2 *) 
max' 1 2;; (* prints 3 *) 
max'' 1 2;; (* prints 1 *) 
max'' 1 2;; (* prints 1 *) 
max'' 1 2;; (* prints 1 *) 

所以我們設計爲每週多態函數有一個持續可變狀態裏面允許使用計數器的預期,而多態功能是無狀態,並且每次調用都重構,儘管我們想要在裏面有一個可變變量。

。這是一個編譯器更喜歡可與任何單一類型的,而不是支承全面多態性可以使用弱多態函數的原因。

+0

爲什麼在函數定義的末尾添加'l'使其具有強多態性? –

+0

是的,這是價值限制。對於像你這樣的情況,獲得完整多態性的經典方法是「eta擴展」,這正是你在第一個函數中所擁有的。 –

+0

@JeffreyScofield我不明白的是'爲什麼增加一個額外的參數會使它變得強壯'。 –

2

類型爲'_a list list -> '_a list的函數是弱多態的。這意味着,如果你調用一個int list list第二個,rev_flatten'_a list list -> 'a listint list list -> int list

不再您可以在這裏閱讀更多關於爲什麼這裏的細節: http://caml.inria.fr/resources/doc/faq/core.en.html

乾杯,

Scott

2

這僅僅是ML-樣式值限制。以前的回答由gasche提供了一些很好的參考文獻:What is the difference between 'a and '_l?

一般來說ML系列適用於簡單的語法測試,看看它是否是安全的,完全概括,那就是,做一個類型完全多態性。如果你概括了一個不安全的情況,程序就會有未定義的行爲(它可能會崩潰或得到錯誤的答案)。所以你只有在安全的時候才需要做。

句法規則被應用,因爲它的(相對)容易記住。一個更復雜的規則已經嘗試了一段時間,但它造成了更多的傷害而不是好的(是普遍的結論)。對ML家族的歷史描述將比我更好地解釋它。

您的其中一個的功能(第二個)被定義爲表達式,即,作爲函數的應用程序。根據價值限制,這不是「安全」的。 (請記住,它只是一個語法測試。)第一個是lambda(fun x - > expr)。這是「安全」的。

這就是所謂的價值限制,因爲它認爲值是安全的。函數應用程序不是(語法)值。 lambda是一個語法值。像[]就是一個值。類似ref []不是一個值。