Skip to content

Instantly share code, notes, and snippets.

@notogawa
Created January 30, 2019 09:07
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save notogawa/c122fc1d75531c4f8db30e6d66832ffc to your computer and use it in GitHub Desktop.
Save notogawa/c122fc1d75531c4f8db30e6d66832ffc to your computer and use it in GitHub Desktop.
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