2016-11-19 166 views
1

this問題中,未標記的聯合被描述爲子類型的一種形式。允許未標記的工會等同於允許類型類?

類型類也是子類型的一種形式。

它們在概念上是否相同?呃他們是,我將如何在Haskell中實現這些?

+4

我認爲Haskell沒有子類型,因爲它會被傳統定義,因爲每個值都有一個_one_類型。類型類只是擴展類型語言以允許用戶定義的多態性的一種方式。也就是說,它讓一個值'x'具有'C a => a'的類型,其中'C'是一組規則'a'必須符合的;但是'x'仍然只有一種類型。將其與OOPy子類型相對比,其中值'x'具有多種類型:其基本類型和從基本類型中繼承的任何類型。 – hao

+1

另一個更迂腐的論點:子類型會抑制Haskell編譯器具有的DHM類型主體類型推斷,而類型類不會。 – hao

+3

詳細說明@ haoformayor的觀點:不要混淆子類型和ad-hoc多態。子類型是ad-hoc多態的一種風格,類型類是一個相當不同的類型。 –

回答

4

類型類也是子類型的一種形式。

他們不是。爲了說明起見,讓我們回到TypeScript examples我在這個問題提到:

如果我們有一個具有聯合類型的值,我們只能訪問成員 通用於所有類型的工會。

interface Bird { 
    fly(); 
    layEggs(); 
} 

interface Fish { 
    swim(); 
    layEggs(); 
} 

function getSmallPet(): Fish | Bird { 
    // ... 
} 

let pet = getSmallPet(); 
pet.layEggs(); // okay 
pet.swim(); // errors 

這裏,getSmallPet返回類型既不是Fish也不Bird,但兩者具有作爲成員的成員共有的FishBird的超類型。 A Fish也是 a Fish | Bird,因此是Bird

與類型類會發生什麼情況是完全不同的:

foo :: Num a => a -> a 
foo x = (x * x) + x 

雖然兩者foo (3 :: Integer)foo (7.7 :: Double)工作,這並不意味着不存在對應於Num(3 :: Integer)(7.7 :: Double)也有一個超類型。相反,所有的Num a => a -> a說的是,你的a選擇應具有的Num一個實例(這是值得強調的是,Num不是一個類型),所以有您所選擇的類型(*)(+)合適的實現。與OOP方法不同,(*)(+)不屬於任何特定類型,因此不需要引入超類型以便與IntegerDouble一起使用它們。

+0

這個答案有很大幫助,謝謝。儘管如此,我還是覺得這兩個概念至少是相關的,因爲'Pet'示例也可以通過類型類來實現。作爲一個問題表達爲:「類型級別約束與未標記的工會一樣強大嗎?」 (儘管這可能更適合作爲後續問題)。 – ThreeFx

+3

@ThreeFx我們可以說,在這種情況下,他們將是實現相同目標的兩種截然不同的方式。順便說一下,值得注意的是,未標記的方面對於討論來說不是必需的 - 如果我們在TypeScript示例中有一個''Oviparous''接口和一個''''''''''''''''''可以擴展的'layEggs'方法,根本區別將保持不變。一個相關的,如果有些切向的問題:[*參數多態性與Ad-hoc多態性*](http://stackoverflow.com/q/6730126/2751851)。 – duplode