Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
module WhatIsInstance where
data Hoge = Foo | Bar
-- 型aが同値関係を持つということを示す型
data ThisIsEq a = ThisIsEq { op :: a -> a -> Bool }
-- 型Hogeが同値関係を持つ証拠となる値
hogeIsEq :: ThisIsEq Hoge
hogeIsEq = ThisIsEq go where
go Foo Foo = True
go Bar Bar = True
go _ _ = False
-- 型Boolが同値関係を持つ証拠となる値
boolIsEq :: ThisIsEq Bool
boolIsEq = ThisIsEq go where
go True True = True
go False False = True
go _ _ = False
-- 任意の型aに対して,"型aが同値関係を持つ" ならば "同値比較が利用できる"
equal :: ThisIsEq a -> a -> a -> Bool
equal eq a b = op eq a b
-- "同値関係を持つという証拠" を "渡し分ける" ことでequalはHogeにもBoolにも対応する
testHogeIsEq = equal hogeIsEq Foo Bar
testBoolIsEq = equal boolIsEq True True
-- しかし,証拠を型によって渡し分けるなんてメンドクサイなぁ
-- equalの型宣言にある a -> a -> Bool の部分から,
-- 勝手に hogeIsEq 使うとか boolIsEq 使うとか"渡し分ける"のを
-- 処理系がやってくれないかなぁ
--
-- \ | | | | | | | | | | /
-- これが > 型クラスとインスタンス <
-- / | | | | | | | | | | \
--
-- まず,型クラスを導入する(ThisIsEq に対応)
class HasEq a where
equal' :: a -> a -> Bool
-- Hogeに対してインスタンスを定義する(hogeIsEqに対応)
instance HasEq Hoge where
equal' Foo Foo = True
equal' Bar Bar = True
equal' _ _ = False
-- Boolに対してインスタンスを定義する(boolIsEqに対応)
instance HasEq Bool where
equal' True True = True
equal' False False = True
equal' _ _ = False
-- equal' の型は, HasEq a => a -> a -> Bool となり,
-- 元の equal の ThisIsEq a -> a -> a -> Bool と対応
-- aの型から適切なHasEq a (元ThisIsEq a) のインスタンスが選択され,
-- "渡し分け"を陽に行わずに同値比較が利用できるようになった
testHogeIsEq' = equal' Foo Bar -- 暗黙にHasEq Hoge (元 hogeIsEq)が選択されている
testBoolIsEq' = equal' True True -- 暗黙にHasEq Bool (元 boolIsEq)が選択されている
-- やったぜ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment