2014-02-27 90 views
1

我想了解Haskell的類型系統。我來到以下幾點:Haskell的對類型

*Main> :t ("Hello", 4) 
("Hello", 4) :: Num t => ([Char], t) 

*Main> :t ("Hello", 'a') 
("Hello", 'a') :: ([Char], Char) 

*Main> :t ("Hello", True) 
("Hello", True) :: ([Char], Bool) 

爲什麼("Hello", 4)的類型不能像別人那樣表示。我原本以爲它是("Hello", 4) :: ([Char], Num)

我已經看到了=>之前。我想知道的是,爲什麼它會造成這種差異?

回答

11

這是因爲Num不是一種類型;它是typeclassNum t => someType意味着t是某種任意類型,它是類型類型的一個實例。借用一些Java/C#術語,您可以將Num視爲接口,而Num t => t是一種通用類型,約束條件是t必須實現接口Num

一般來說,您可以在=>箭頭的左側找到類型類約束,右邊的類型體。我們可以有多個類的約束,例如(Num a, Num b) => (a, b),它將表示兩個任意數字類型的元組的類型。我們也可以有零級限制,在這種情況下=>被省略。

在Haskell中,數字文字可以表示任何類型,它是Num的一個實例。字面4可能表示一個浮點數或一個整數,或者(如果你定義了一些更奇特的實例)甚至一個函數。

2

Num是一個typeclass。類型類有些(但不是真的)像OO接口。不同的類型實現了類型類型的功能,允許多態。

例如,有一個標準的Eq類,其被定義爲(你可以得到這個在ghci中與:info Eq

class Eq a where 
    (==) :: a -> a -> Bool 
    (/=) :: a -> a -> Bool 

這意味着,可以編寫功能等isMember :: (Eq a) => a -> [a] -> Bool。該函數採用a類型的實現(有一個實例)Eq和相同類型的列表,並返回一個布爾值。這泛型類型的簽名意味着您可以做

elem 'c' "abcd" 
elem 4 [1,2,3] 

它將編譯,但你不能做

elem 'c' [1,2,3] 

現在,回到你原來的問題。 當你在ghci中鍵入一個數字時,它試圖給這個數字一個最普遍的數字。它不知道5Int還是Integer,或者甚至是Double。因此,文字的類型是(Num t) => t,意思是「這個東西可以是任何類型的t比實現了Num類型類)。

不同的表現會給你更多的具體類型。例如,5 `div` 3具有類型(Integral a) => a,因爲divIntegral類的一種方法

如果你想了解更多關於類型分類,this是一個很好的鏈接。

2

數字文字是一種特殊情況,4可能是例如,解釋爲IntInteger,並且編譯器不會爲您做出該選擇,但採用常見類型類型Num(正如其他答案已經解釋過的)形式中的一種「最小公分母」。

附加點我儘量讓是,如果你在這一點上更具體的,古怪消失:

-- specify Int explicitly 
*Main> :t ("Hello", 4 :: Int) 
("Hello", 4 :: Int) :: ([Char], Int) 

-- specify Integer explicitly 
*Main> :t ("Hello", 4 :: Integer) 
("Hello", 4 :: Integer) :: ([Char], Integer) 

-- use an Int result from an expression 
*Main> :t ("Hello", length [1,2,3]) 
("Hello", length [1,2,3]) :: ([Char], Int)