鍵入同義詞系列
型別同義詞族只是型別級函式:它們將引數型別與結果型別相關聯。它們有三種不同的型別。
封閉式同義詞系列
這些工作與普通的值級 Haskell 函式非常相似:你指定了一些子句,將某些型別對映到其他型別:
{-# LANGUAGE TypeFamilies #-}
type family Vanquisher a where
Vanquisher Rock = Paper
Vanquisher Paper = Scissors
Vanquisher Scissors = Rock
data Rock=Rock; data Paper=Paper; data Scissors=Scissors
開啟型別同義詞系列
這些工作更像是型別類例項:任何人都可以在其他模組中新增更多子句。
type family DoubledSize w
type instance DoubledSize Word16 = Word32
type instance DoubledSize Word32 = Word64
-- Other instances might appear in other modules, but two instances cannot overlap
-- in a way that would produce different results.
類關聯型別同義詞
開放式家庭也可以與實際類相結合。這通常是當,例如與相關聯的資料的家庭 ,一些類的方法需要額外的輔助物件,而這些輔助物件可以是不同的例項不同,但可能也共享。一個很好的例子是 VectorSpace
類 :
class VectorSpace v where
type Scalar v :: *
(*^) :: Scalar v -> v -> v
instance VectorSpace Double where
type Scalar Double = Double
μ *^ n = μ * n
instance VectorSpace (Double,Double) where
type Scalar (Double,Double) = Double
μ *^ (n,m) = (μ*n, μ*m)
instance VectorSpace (Complex Double) where
type Scalar (Complex Double) = Complex Double
μ *^ n = μ*n
注意在前兩個例項中,Scalar
的實現是一樣的。對於相關的資料族,這是不可能的:資料族是單射的 ,型別同義詞族不是。
雖然非注入性開闢瞭如上所述的一些可能性,但它也使型別推理更加困難。例如,以下內容不會進行型別檢查:
class Foo a where
type Bar a :: *
bar::a -> Bar a
instance Foo Int where
type Bar Int = String
bar = show
instance Foo Double where
type Bar Double = Bool
bar = (>0)
main = putStrLn (bar 1)
在這種情況下,編譯器無法知道要使用的例項,因為 bar
的引數本身只是一個多型的 Num
文字。並且型別函式 Bar
不能在反方向中解析,正是因為它不是單射 † 而且因此不可逆(可能有多個型別與 Bar a = String
)。
† 由於只有這兩種情況下,它是真正射,但是編譯器不知道有人不增加更多的例項以後,從而打破行為。