2010-04-20 54 views
5

如何ML在下面的函數定義進行了類型推斷:解釋ML類型推斷的C++程序員

let add a b = a + b 

是它喜歡在那裏,直到模板實例化後的點沒有進行類型檢查C++模板如果該類型支持必要的操作,該函數可以工作,否則會引發編譯錯誤?

即,例如,下面的函數模板

template <typename NumType> 
NumType add(NumType a, NumType b) { 
    return a + b; 
} 

將爲

add<int>(23, 11); 

工作,但不會爲

add<ostream>(cout, fout); 

的工作是什麼,我猜測是正確的或ML類型推斷的工作方式不同? PS:對不起,我的英語不好;這不是我的母語。

+1

你問關於類型推斷還是類型檢查? – sepp2k 2010-04-20 19:24:56

+0

推斷。在我的示例中,從ML函數定義中推斷出哪種類型? – 2010-04-20 19:26:50

回答

5

我建議你看看這篇文章:What is Hindley-Milner? (and why is it cool)

這裏是他們用來解釋類型推斷最簡單的例子(這不是ML,但這個想法是一樣的):

def foo(s: String) = s.length 
// note: no explicit types 
def bar(x, y) = foo(x) + y 

看看bar的定義,我們可以很容易地看到它的類型必須是(String,Int)=> Int。簡而言之,這是類型推斷。閱讀整篇文章以獲取更多信息和示例。

我不是C++專家,但我認爲模板是更接近於通用性/參數性的東西,這是不同的東西。

+0

我不明白爲什麼fun func(a,b)= a + b'中的'a'和'b'類型不是推斷爲'real'(浮點)的例子。那是因爲'int'優先於'real'嗎? – ZhekaKozlov 2013-10-20 18:01:20

4

ML使用Hindley-Milner type inference。在這個簡單的例子中,它所要做的就是查看函數的主體,並看到它使用參數+並返回該參數。因此,它可以推斷參數必須是+接受的參數類型(即整數),並且該函數返回+返回的類型(也是int)。因此add的推斷類型是int -> int -> int

注意,在SML(而不是CAML)+也爲其他類型的比INT定義,但它仍然會推斷INT當有多個可能性(即你定義不能用來添加花車add功能) 。

5

我認爲試圖將ML類型推斷與C++中的幾乎任何事情聯繫起來都比理解更容易導致混淆。 C++根本沒有任何事情與推理類型完全相同。

C++中沒有明確輸入的唯一部分是模板,但是(大部分)它們支持泛型編程。像你提供的C++函數模板可能同樣適用於一組無限的類型 - 例如,您使用的代碼使用NumType作爲模板參數,但可以使用字符串。一個程序可以實例化你的add在一個地方添加兩個字符串,在另一個地方添加兩個數字。

ML類型推斷不適用於泛型編程。在C或C++中,您明確定義了參數的類型,然後編譯器會檢查您嘗試對該參數執行的所有操作都是由該類型允許的。 ML反過來說:它看着你用這個參數做的事情,並且計算出有哪些類型的可以讓你做這些事情。如果你試圖做相互矛盾的事情,它會告訴你沒有類型可以滿足約束條件。

這在C或C++中幾乎是不可能的,主要是因爲允許的所有隱式類型轉換。舉個例子,如果我在ML中有類似a + b,它可以立即得出結論:ab必須是整數 - 但在C或C++中,它們幾乎可以是整數或指針或浮點類型的任意組合(帶約束他們不能兩個都是指針)或使用過載的定義類型operator+(例如,std::string)。在ML中,查找類型在最壞的情況下可能是指數級的,但幾乎總是非常快。在C++中,我估計它更頻繁地呈指數形式,並且在很多情況下可能會受到不足的限制,因此給定的函數可能具有許多不同的簽名中的任何一個。

+2

C++ 0x有''auto'關鍵字的本地類型推斷(就像C#,但有點更一般)。但這與欣德利米爾納相去甚遠。基本上,它只適用於聲明點,並且只有當變量立即用常量表達式初始化時才起作用。 – 2010-04-20 23:48:33