標籤:

Haskell 的 Typeclass 怎麼理解?

中文對應哪個關鍵詞?

然後怎麼理解這段英文介紹,我感覺不好懂(Java 不懂的情況下)。

A typeclass is a sort of interface that defines some behavior.

If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes.

A lot of people coming from OOP get confused by typeclasses because they think they are like classes in object oriented languages.

Well, theyre not. You can think of them kind of as Java interfaces, only better.


如果從工程的角度來看,Haskell的type class解決了以下幾類問題

1、類型推導如何兼容重載函數

2、定義OO語言所缺失的concept /*mapping*/(如C#的IComparable&和Haskell的Sort,事實上任何時候C#的IComparable&都不應該是一個介面,因為每個類型只會實現一次,所以他應該是concept,對於任何T應該是靜態的,然而OO的語言就是對這些東西有著微妙的敵意)。C++的模板的一些奇葩的功能替代了concept,然而一旦程序寫錯了,錯誤信息特別糟糕,所以他們還正在試圖發明一次concept。

3、演算法的擴展。之前誰的一篇文章講到了類型的兩種擴展。第一種擴展是針對函數擴展,你有一些固定的類型,你可以不斷的寫新的函數來在運行的時候動態重載他們,就像Visitor模式乾的一樣。第二種是針對類型的擴展,這個就是大家熟悉的虛函數,你先定義好一系列的函數,於是你就可以無限的擴展新的類型來實現這些函數。Haskell乾的就傾向於第一種,沒有辦法做第二種,因為他的data聲明是封閉的,而type class的instance是開放的。其中固定的類型指的就是data的各種構造函數。F#也有類似的功能,你們可以把Haskell的data和type class翻譯過去,然後編譯出來之後,反編譯成C#,就什麼都明白了。


補充一下其他答案里好像漏掉的一點:type class其實更嚴謹的說法叫constructor class。。以下答案中「type class」均指代constructor class。

以最簡單的show函數為例,show :: Show a =&> a -&> String,只要某個值type是Show類的instance,就可以調用show函數。另外一個例子是fmap :: Functor f =&> (a -&> b) -&> f a -&> f b。注意到了什麼?f是Functor類的instance,但是f並不是一個類型;f a和f b才是類型。換句話說,能夠成為某個類的instance的東西,並不一定是type,還有可能是type constructor。。

如果把type看成另一種value的話,那麼type constructor其實不過就是type function而已。。然後,比如a -&> b就可以表述為(-&>) a b,而這個(-&>)就是一個type function,而type function也支持自動的currying。

怎樣區分一個東西是type和type function?你需要一個叫做kind的概念。。規定Int,Bool之類的類型的kind為*,然後像Functor/Monad等類的成員的kind為* -&> *,而(-&>)的kind為* -&> * -&> *。。然後kind為*的constructor才能夠描述值類型,而其他kind的東西都可以看成type function。。然後,定義一個type class的時候,他的instance可以是一個具體的type(也就是說kind為*),也可以是其他kind的constructor。。

然後在實現編譯器的時候,type inference之前還有一步簡單的kind inference。。確保不會出現type X = Int Int之類的kind錯誤。

更強的拓展,dependent type什麼的,還沒學就不提了。。

ref:

A system of constructor classes: overloading and implicit higher-order polymorphism

https://www.haskell.org/onlinereport/haskell2010/


Demystifying Type Classes


Haskell的Typeclass從範疇論來看就是一個範疇中的態射(morphism),而type就是範疇中的對象(collection),instance一個Typeclass後就得到一個範疇(category)。比如簡單的Eq這個Typeclass,其定義如下:

class Eq a where
(==), (/=) :: a -&> a -&> Bool
x == y = not (x /= y)
x /= y = not (x == y)

重寫Eq Int的定義如下:

instance Eq Int where
(==) = eqInt

這裡eqInt是我們自己定義的比較整數是否相等的函數。

這樣,我們就得到了一個基於包含Int和Bool這兩個type的對象集(collection)和以Eq為態射(morphism)的範疇。


」class of types」,可以理解為對某一系列類型的抽象(即高階類型)

它表示某種抽象行為,這種行為的具體實現 要由它的具體類型參數決定

在scala里沒有這個關鍵字,typeclass 則成為一種模式,通過泛型來描述某種通用行為,

對每個想要用到這種行為的具體類型,在實現時行為部分並不放在類型自身中,而是通過實現一個type class實例(對泛型具化),最後在調用時(通過隱 式參數)讓編譯器自動尋找行為的實現

優點

  • 抽象分離:參考前面的
  • 可組合性:[T: Comparable2]語法 可以指定多個類型如:[T: Comparable2 : Order] 比要求某個抽象介面或者介面組合要靈活的多,並且可以組合不同type class的實現
  • 可覆蓋性:可利用隱式系統覆蓋Type class的默認實現
  • 類型安全:都在編譯期

對,我就是來安利scala的

-------------------------------------------

type classes 是語言對於qualified types 的實現形式,qualified types 則是對polymorphic types加上了predicate限定,使得其處於polymorphic types和monomorphic types之間,功能上實現了parametric polymorphism + overloading。

type classes + type constructors (+ kind system) 的應用被稱為:Constructor classes

https://www.cs.ox.ac.uk/files/3432/PRG106.pdf

http://people.csail.mit.edu/dnj/teaching/6898/papers/wadler88.pdf

http://www.cs.tufts.edu/~nr/cs257/archive/mark-jones/fpca93.pdf


簡單來說就是可以實現給靜態類型語言的 polymorphism 加上 constraints。

而且 typeclass 的用法遠不止於此,一種玩法是實現 type function,見:https://www.haskell.org/haskellwiki/GADTs_for_dummies


中文應該叫做類型類,實際上在OO語言里是找不到類似的概念的。類型類定義了一組函數,但是並沒有實現,因此說是一個interface,如果一個類型要支持一個類型類,就要使用instance來定義,也就是給你的類型實現這個類型類指定的介面。

比如,我定義一個類型:

data Demo = Demo1 String

| Demo2 Int

一個基本的需求就是我想列印出這個類型的數據,這有一個標準的類型類,Show, 其定義為:

class Show m where

show :: a -&> String

為了讓Demo類型的數據也能使用show函數,我們就要實現它:

instance Show Demo where

show (Demo1 str) = str

show (Demo2 num) = show num

於是,當我們有一個Demo類型的數據,比如d時,可以這樣:

show d


Bounded quantification


我不知道問問題的同學有什麼語言的基礎,不好舉例子啊

這個東西說起來確實類似java里的介面。定義了一種規格

比如Eq表示可判等的一類事物,具有==和/=方法

比如Ord表示有序(可比較)的一類事物,具有&>,&<,&>=,&<=等方法

而一個具體類型,比如Int,它既是Eq的實例,也是Ord的實例,也就是說Int是可判等,可比較的,因此Int具有以上所有這些方法


還是一個初學者對typeclass的理解:typeclass確實最像Java中的Interface,但比它更靈活。因為

  • 你可以動態的為一個Type實例化某個typeclass,而Java中Class的定義只能到Class相關的代碼中去修改,並且Class繼承哪些介面也是固定的。從這個意義上來說,typeclass有點像Python中的修飾。

  • 甚至,在不同的模塊中,對同一個Type實例化同一個typeclass可以有不同的實現,只要不導出產生衝突即可。我專門測試了一下,結果可以邏輯顛倒:

--ClassDefine.hs

module ClassDefine (BasicEq(..)) where

class BasicEq a where
isEqual :: a -&> a -&> Bool

-- ModuleA.hs

module ModuleA (demoA) where

import ClassDefine(BasicEq(..))

instance BasicEq Bool where
isEqual True True = True
isEqual False False = True
isEqual _ _ = False

demoA :: Bool -&> Bool -&> Bool

demoA = isEqual

--ModuleB.hs
module ModuleB (demoB) where

import ClassDefine(BasicEq(..))

instance BasicEq Bool where
isEqual True True = False
isEqual False False = False
isEqual _ _ = True

demoB :: Bool -&> Bool -&> Bool

demoB = isEqual

-- TestTypeClass.hs
import ModuleA(demoA)
import ModuleB(demoB)


覺得像C++中的concept.

[1] Stackoverflow: How are c++ concepts different to Haskell typeclasses?

[2] OOP vs type classes

[3] Generic programming with C++ concepts and
Haskell type classes—a comparison, http://publications.lib.chalmers.se/records/fulltext/local_124669.pdf


typeclass從某種方面看,和java的interface有點像。規定了一個類型必須具有什麼樣的操作。這樣某些函數可以只要求某個類型具有某種介面而不是要求需要某個名字,從而達到了所謂的范性。比如,排序,只需要知道類型比較大小的方法就可以了,haskell中就是Ord,這樣所有Ord的instance,都可以應用排序函數(你自己定義的任何類型實現了這個typeclass也可以)。


named overloading


對象中的類

結構類 描述對象的結構共性

typeclass

行為類 描述實例的行為共性


我理解的 Typeclass 是用來構造一個具體類型的初始模型,這個模型上定義了一系列行為函數,這些函數在 Typeclass 中不一定有具體的實現,但一定有類型聲明。

當某個具體的類型通過 instance 關鍵字變成這個 Typeclass 的實例時,這個具體的類型就獲得了 Typeclass 這個初始模型上定義的一系列行為函數,當然這個具體的類型也可以根據行為函數的類型聲明給出自己的一套實現方式,這樣就達到了重載的效果。

前面的回答也提到了,Typeclass 其實就是一系列行為的抽象。


推薦閱讀:

為什麼haskell里需要monoid?
為什麼 Haskell 始終沒法流行呢?
Robert Harper 不支持Haskell 的理由是?

TAG:Haskell |