『入門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
こうなります。