2011-12-15 26 views
11

當使用交互式GHC解釋,有可能要求推斷類型的表達式:GHCi如何爲類型變量選擇名稱?

Prelude> :t map 
map :: (a -> b) -> [a] -> [b] 

看來,它需要的類型變量的名稱從簽名,因爲mapdefined作爲

map :: (a -> b) -> [a] -> [b] 
map _ []  = [] 
map f (x:xs) = f x : map f xs 

在Prelude中。這很有道理!我的問題是:在沒有給定簽名時如何選擇類型變量名稱?

一個例子是

Prelude> :t map fst 
map fst :: [(b, b1)] -> [b] 

它撿起名bb1。很明顯,重命名必須發生,而只是開始ab,......將給予

map fst :: [(a, b)] -> [a] 

代替,我覺得稍微更具可讀性。

回答

13

據我所知,ghci選擇名稱的順序與它推斷的類型相同。它使用您提到的命名方案來決定結果的類型名稱,即[b],因爲這是在map的定義中指定的類型名稱。然後它決定作爲map的第一個參數的函數也應該返回b類型的東西。

因此,要命名的其餘類型變量是參數元組中的第二個元素的類型變量,其值爲fst,同樣,它查看fst的定義以決定使用哪個名稱。 fst :: (a, b) -> a的定義,因此b將是此處的首選名稱,但由於b已被佔用,因此它會附加1,以便它變爲b1

我認爲這個系統在你不處理任意類型的情況下具有優勢,就像這裏的情況一樣。如果得到的類型看起來是這樣的,例如:

castAdd :: (Num n, Num n1, Num n2) => n -> n1 -> n2 

...這可以說是比更具可讀性:

castAdd :: (Num a, Num b, Num c) => a -> b -> c 

...因爲你可以主要依賴於n#表示一個數字類型,因爲Num的類定義是class Num n where ...

編輯:是的,我知道castAdd是不可能實現的,但它只是一個類型的例子。

+1

謝謝,這是一個很好的解釋!我沒有想到你想要重新命名幾個`n`但保持相關的情況。 – 2011-12-15 14:26:06