類型類
在電腦科學中,類型類(type class),是支援特設多型的型別系統構造。這是通過向參數多型類型的類型變數增加約束完成的。這種約束典型的涉及到一個類型類T
和一個類型變數a
,並意味着a
所能實例化的類型,其成員必須支援關聯於T
的多載運算。
類型類首先在Haskell中實現,當時Philip Wadler和Stephen Blott提出它,作為對Standard ML的eqtype
的擴充[1][2],並且最初構想為以本原方式實現多載算術及等式算符的一種途徑[3][4]。
對比於Standard ML的「eqtypes」,在Haskell中通過使用類型類多載等式算符,不要求編譯器前端或底層型別系統的廣泛修改[5]。
自從它們創立之後,已經發現了類型類的很多其他應用。
概述
定義類型類需要通過規定一組函數或約束名字,它們分別具有同在的類型,它們對屬於這個類的所有類型都必須存在。在Haskell中,類型可以被參數化,意圖包含允許等式的類型一個類型類Eq
,可以如下這樣聲明:
class Eq a where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x /= y = not (x == y)
x == y = not (x /= y)
這裏的a
是類型類Eq
的一個實例,並且a
定義的函數簽章,針對了2個函數(等式和不等式函數),它們每個都接受2個類型a
的實際參數並返回一個布林值。這個聲明可以讀作:「類型a
屬於類型類Eq
,如果在其上定義了有適當類型的,叫做(==)
、(/=)
的的函數。」
編程者可以使任何類型t
成為給定類型類C
的成員,通過使用「實例聲明」 為特定類型t
實現所有的C
方法。如果編程者定義一個新的記錄資料類型Foo
,可以接着使這個新類型成為Eq
的實例,通過以任何他們認為合適的方式,提供在類型Foo
的值之上的等式函數和不等式函數,例如:
data Foo = Foo {x :: Integer, str :: String}
instance Eq Foo where
(Foo x1 str1) == (Foo x2 str2) = (x1 == x2) && (str1 == str2)
編程者可以接着如下這樣定義函數elem
,它確定一個元素是否在一個列表之中:
elem :: Eq a => a -> [a] -> Bool
elem y [] = False
elem y (x:xs) = (x == y) || elem y xs
函數elem
的類型a -> [a] -> Bool
具有上下文Eq a
,將參數多型函數的類型變數a
可包括的類型,約束為屬於Eq
類型類的那些類型。Haskell中的 =>
可表示「類型類繼承」或「類型約束」。函數elem
可應用於屬於Eg
類型類的任何類型的元素和這個類型的列表二者之上。
注意類型類不同於物件導向程式設計語言中的類。特別是,Eq
不是一個類型:沒有類型Eq
的值這種東西。類型變數a
有種類(kind) ,在最新的GHC發行中叫做Type
[6]。意味着Eq
的種類是:
Eq :: Type -> Constraint
高種類多型
類型類不但接受種類Type
的類型變數,它可以接受任何種類的類型變數。這些有更高種類的類型類有時叫做構造子類,這裏的構造子指稱的是類型構造子比如Maybe
,而非數據構造子比如Just
。例如單子類Monad
:
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
m
應用到一個類型變數上的事實,指出了它有着種類Type -> Type
,就是說它接受一個類型並返回一個類型,因而Monad
的種類是:
Monad :: (Type -> Type) -> Constraint
多參數類型類
類型類允許多個類型參數,因此類型類可以被看作在類型上的關係[7]。例如,在GHC標準庫中,類IArray
表達一個通用不可變陣列介面。在這個類中,類型約束IArray a e
意味着a
是一個陣列類型,它包含類型e
的元素。例如,在多型上的這種限制被用來實現開箱陣列類型。
函數依賴
在Haskell中,類型類已經被精製為允許編程者聲明在類型參數之間的函數依賴,這個概念受到關聯式資料庫理論中的函數依賴的啟發[8][9]。就是說,編程者可以斷言對類型參數的某個子集的給定指派,唯一性的確定餘下的類型參數。例如,承載一個類型s
的狀態參數的,一個一般性的單子m
,滿足類型類約束Monad.State s m
。在這個約束中,有函數依賴m -> s
。這意味着對於類型類Monad.State
的一個給定單子m
,從m
能訪問到的狀態類型是被唯一性確定的。這會輔助編譯器進行類型推論,還能輔助編程者進行類型導向編程。
Simon Peyton-Jones因其複雜性而反對在Haskell中介入函數依賴[10]。
運算子多載的其他方式
在Standard ML中,「等式類型」的機制粗略的對應於Haskell的內建類型類Eq
,但是所有等式算符都自動的由編譯器匯出。編程者的過程控制局限於,指定在一個結構中哪些類型成員是等式類型,和在多型類型中哪些類型變數涉及等式類型。
SML和OCaml的模組和函子可以扮演類似於Haskell的類型類的角色,原則區別在於類型推論的角色,它使得類型類適合於特設多型[11]。OCaml的物件導向子集是某種程度上與類型類有可比性的另一種方式。
有關概念
用於多載數據的一個類似概念(實現於GHC中)是類型家族[12]。
在Clean中的類型類與Haskell相似,但是有稍微不同的語法。
Rust支援trait,這是具有一致性的有限形式的類型類[13]。
Mercury有類型類,卻不完全同於Haskell。
在Scala中,類型類是編程慣例,可以用現存語言特徵比如隱式參數來實現,本身不是獨立的語言特徵。由於它們在Scala中的這種實現方式,在有歧義的情況下,有可能顯式的指定哪種類型類別實例用作在代碼中特定位置上的類型。但是,這不必然有益處,因為有歧義的類型類別實例是易於出錯的。
證明輔助Coq在新近版本也支援類型類。不像在平常程式語言中那樣,在Coq中,在類型類別定義內陳述的任何類型類定律(比如單子定律),在使用它們之前,必須對每個類型類別實例進行數學證明。
參見
- 多型 (電腦科學)
- 運算子多載 - 類型類的應用之一
- 單子 (函數式程式設計),函子 (函數式程式設計) - 是類型類的例子
- 概念 (C++)(自從C++20)
參照
- ^ Morris, John. Type Classes and Instance Chains (PDF). 2013 [2021-02-08]. (原始內容存檔 (PDF)於2020-11-04).
- ^ Wadler, Philip. How to make ad-hoc polymorphism less ad hoc. October 1988.
- ^ Kaes, Stefan. Parametric overloading in polymorphic programming languages. Proc. 2nd European Symposium on Programming Languages. March 1988. doi:10.1007/3-540-19027-9_9.
- ^ Wadler, Philip; Stephen Blott. How to make ad-hoc polymorphism less ad hoc. Proc. 16th ACM Symposium on Principles of Programming Languages. January 1989 [2021-02-08]. (原始內容存檔於2016-03-11).
- ^ Appel, Andrew; David MacQueen. Standard ML of New Jersey. Proc. 3rd International Symposium on Programming Language Implementation and Logic Programming. June 1991 [2021-02-08]. (原始內容存檔於2008-05-09).
- ^
Type
(頁面存檔備份,存於互聯網檔案館) fromData.Kind
appeared in version 8 of the Glasgow Haskell Compiler - ^ Haskell' page MultiParamTypeClasses (頁面存檔備份,存於互聯網檔案館).
- ^ Mark Jones. Type Classes with Functional Dependencies (頁面存檔備份,存於互聯網檔案館). From Proc. 9th European Symposium on Programming. March, 2000.
- ^ Haskell' page FunctionalDependencies (頁面存檔備份,存於互聯網檔案館).
- ^ 存档副本. [2021-02-10]. (原始內容存檔於2014-12-25).
- ^ Dreyer, Derek; Robert Harper; Manuel M.T. Chakravarty. Modular Type Classes. April 2006 [2021-03-01]. (原始內容存檔於2007-05-19).
|book-title=
被忽略 (幫助) - ^ GHC/Type families - HaskellWiki. [2021-02-10]. (原始內容存檔於2014-10-28).
- ^ Specialization, coherence, and API evolution · Aaron Turon. [2021-02-10]. (原始內容存檔於2020-11-12).
外部連結
- A Gentle Introduction to Haskell, Version 98, chapter 5. Type Classes and Overloading (頁面存檔備份,存於互聯網檔案館). June 2000.
- Implementing, and Understanding Type Classes (頁面存檔備份,存於互聯網檔案館). 2014-11-13.