鍵入同義詞系列

型別同義詞族只是型別級函式:它們將引數型別與結果型別相關聯。它們有三種不同的型別。

封閉式同義詞系列

這些工作與普通的值級 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)。

由於只有這兩種情況下,它真正射,但是編譯器不知道有人不增加更多的例項以後,從而打破行為。