第七章:型別類

夢飛發表於2017-02-26

型別類typeclass是Haskell中最出名的魔法之一。型別推斷系統System FC with roles

型別類的實現包括型別宣告例項宣告兩部分。

1.例項宣告 instance declaration

在第二章data時的例子中

data Position = Cartesian Double Double | Polar  Double Double 

Cartesian 3 4 ==  Polar 0.92729521 5
--?

因為資料型別Position不是Eq的一個例項,GHC拒絕編譯程式,我們需要使用例項宣告來解決這個問題

instance Eq Position where
    Cartesian x1 y1 == Cartesian x2 y2  = (x1 == x2) && (y1 == y2)
    Polar x1 y1 == Polar x2 y2          = (x1 == x2) && (y1 == y2)
    Cartesian x y == Polar a r          = (x == r * cos a) && (y == r * sin a)
    Polar a r == Cartesian x y          = (x == r * cos a) && (y == r * sin a)

Haskell 中有一長串Eq的例項:Bool, Char, Int, Word, () ... Prelude裡匯出的基本資料型別都是Eq的例項。

enter image description here

2.類宣告

類宣告使用的class語法

class ClassName typeVariable where
      method1 :: type1
      method2 :: type2
      ...

      method1 = default1
      method2 = default2
      ...


class Eq a where
    (==), (/=) :: a -> a -> Bool

    x /= y = not (x == y)
    x== y = not (x /= y )

3.型別類的實現

例項宣告和類宣告共同構成了Haskell 的型別類語法,我們把使用class宣告出來的型別叫做型別類。例如比較是否相等的Eq類,比較大小的Ord類,數值的Num類等。

Haskell中,型別類用了約定型別的行為,和型別對應的值沒有任何關係,只有當試圖使用Eq a限定型別a的時候,我們才真正用到了例項宣告中的函式。編譯器會自動幫助我們選擇符合型別類約束的型別實現型別類。

下圖展示了標準的Haskell類 Standard Haskell Classes From Haskell 2010 Language Report

Standard Haskell Classes

  • 層級和約束

上面的圖表中,有一條從Eq到Ord的線,代表Eq是Ord的父級型型別,意思是說,凡是可以比較大小的型別,都一定要能比較是否相等,這在Ord的型別宣告中被寫進了約束。 enter image description here

  • 推導(derive)型別類

Haskell Report 中,規定這些型別類可以被推導: Eq, Ord, Enum, Bounded, Show和Read

  • Show/Read

The Read and Show classes are used to convert values to or from strings. All Prelude types, except function types and IO types, are instances of Show and Read.

    type ReadS a = String -> [(a,String)]
    type ShowS = String -> String
    class Read a where
            readsPrec :: Int -> ReadS a
            readList :: ReadS [a]
            -- ... default decl for readList given in Prelude

    class Show a where
            showsPrec :: Int -> a -> ShowS
            show :: a -> String
            showList :: [a] -> ShowS
            showsPrec _ x s = show x ++ s
            show x = showsPrec 0 x ""
            -- ... default decl for showList given in Prelude

相關文章