『入門Haskell』練習問題例解(12)

p.106です。

(1) MaybeはOrd a => Ord (Maybe a)でもあります。このインスタンス宣言を行いなさい。またShow a => Show (Maybe a)のインスタンス宣言も行いなさい。
(2) 2章で見たように、Ordの宣言の概略は次のようになっています。(中略)これにデフォルトの定義を加えることで、必要最低限の関数だけ用意すれば動作するようにしなさい。

Maybe

MyMaybe型を作ります。derivingを使ってよいなら

data MyMaybe = data MyMaybe a = MyNothing | MyJust a deriving (Eq, Ord, Show)

で一発です。使わなければ

data MyMaybe a = MyNothing | MyJust a

instance (Eq a) => Eq (MyMaybe a) where
	MyNothing == MyNothing = True
	MyJust x  == MyJust y  = x == y
	_         == _         = False

instance (Ord a) => Ord (MyMaybe a) where
	compare MyNothing  MyNothing  = EQ
	compare MyNothing  _          = LT
	compare _          MyNothing  = GT
	compare (MyJust x) (MyJust y) = compare x y

instance (Show a) => Show (MyMaybe a) where
	show MyNothing           = "MyNothing"
	show (MyJust x)          = "MyJust" ++ show x

こんな感じになると思います。ただしこの定義だと show (MyJust (MyJust 1)) は "MyJust (MyJust 1)" ではなく "MyJust MyJust 1" となってしまいます。何とかしたいのですが…。

Ord

MyOrd型クラスを作ります。関数は myCompare, (@>), (@<), (@>=), (@<=), myMax, myMin とします。
はじめ、スーパークラスにはEq型クラスをそのまま使おうと思ったのですが、(==) と (/=) だけ@が頭についてないのは何となく気持ち悪いなあと思ったのでMyEq型クラスを用意することにしました。ついでにOrdering型に代えてMyOrdering型を使うことにしました。

class MyEq a where
	(@==), (@/=) :: a -> a -> Bool
	x @== y = not (x @/= y)
	x @/= y = not (x @== y)

data MyOrdering = MyLT | MyEQ | MyGT

instance MyEq MyOrdering where
	MyLT @== MyLT = True
	MyEQ @== MyEQ = True
	MyGT @== MyGT = True
	_    @== _    = False

class MyEq a => MyOrd a where
	myCompare                :: a -> a -> MyOrdering
	(@>), (@<), (@>=), (@<=) :: a -> a -> Bool
	myMax, myMin             :: a -> a -> a
	x @> y  = myCompare x y @== MyGT
	x @< y  = myCompare x y @== MyLT
	x @>= y = myCompare x y @/= MyLT
	x @<= y = myCompare x y @/= MyGT
	myMax x y | x @>= y   = x
		 | otherwise = y
	myMin x y | x @<= y   = x
		 | otherwise = y

ためしに data Alpha = A | B | C | D という型に順序を入れてみます。

data Alpha = A | B | C | D deriving Show

instance MyEq Alpha where
	A @== A = True
	B @== B = True
	C @== C = True
	D @== D = True
	_ @== _ = False

instance MyOrd Alpha where
	myCompare A A = MyEQ
	myCompare A _ = MyLT
	myCompare _ A = MyGT
	myCompare B B = MyEQ
	myCompare B _ = MyLT
	myCompare _ B = MyGT
	myCompare C C = MyEQ
	myCompare C D = MyLT
	myCompare D C = MyGT
	myCompare D D = MyEQ

GHCiで結果が確認できるようにShow型クラスを継承させました。

*Main> myMax C B
C
*Main> myMin A A
A

こうなります。