第10章 型とクラスの定義 #5

10.6 クラスとインスタンスの宣言

前にも書いたけど、Haskellのクラスは型クラスで、型クラスのインスタンスは型。 最初はBool型がEqクラスを実装する例。自分でも手を動かしたかったので、Bool型とEqクラスを自分で定義してみる。演算子はちょっと悩んだけど、%==%!=にしてみた。

data Bool_ = True_ | False_

class Eq_ a where
  (%==) :: a -> a -> Bool
  (%!=) :: a -> a -> Bool
  x %!= y = not (x %== y)

instance Eq_ Bool_ where
  False_ %== False_ = True
  True_  %== True_  = True
  _      %== _      = False

Haskellの型クラスはJavaC#のインターフェースみたいなものだけど、関数のデフォルト実装を書けるところは違うね。

続いてEqクラスを拡張したOrdクラスの例。C#だとIComparable<T>はIEquatable<T>を拡張したインターフェースじゃないけど。

class Eq_ a => Ord_ a where
  (%<)  :: a -> a -> Bool
  (%<=) :: a -> a -> Bool
  (%>)  :: a -> a -> Bool
  (%>=) :: a -> a -> Bool
  min   :: a -> a -> a
  max   :: a -> a -> a
  min x y | x %<= y   = x
          | otherwise = y
  max x y | x %>= y   = x
          | otherwise = y

instance Ord_ Bool_ where
  False_ %<  True_ = True
  _      %<  _     = False
  b      %<= c     = (b %< c) || (b %== c)
  b      %>  c     = c %< b
  b      %>= c     = c %<= b

インスタンスの自動導出

おおー、楽だ。Showクラスとか書くの面倒だなと思ってたけど、こんな機能があるならOKだ。 derivingの後ろにクラスを複数書く場合は()で囲む必要あり。

data Shape = Circle Float | Rect Float Float
  deriving (Eq, Ord)

モナド

前に使ったParser型を本当のモナドにした時に、Monadクラスを実装していたこと(と、MonadPlusクラスを実装していたこと)はすでに知ってた。 せっかくなので、Maybe_型を自分で書いてみよう。

data Maybe_ a = Nothing_ | Just_ a
  deriving Show

instance Monad Maybe_ where
  return x       = Just_ x
  Nothing_ >>= _ = Nothing_
  Just_ x  >>= f = f x