. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
.
......
すごいHaskell読書会 in 大阪 #6— 6. 型や型クラスを自分で作ろう (2) —
@cojna
2013年 3月 8日
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
本日の内容
7.7 再帰的なデータ構造
7.8 型クラス 中級講座
7.9 Yes と No の型クラス
7.10 Functor 型クラス
7.11 型を司るもの、種類
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
前回の復習
.データ型の作り方........data Maybe a = Nothing | Just a deriving (Eq, Ord)
Maybe : 型コンストラクタ (具体型ではない)f :: Maybe → Int のような関数は作れない
a : 型引数 (具体型)
Maybe a : 具体型
Just : 値コンストラクタ
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
リスト
[3, 4, 5, 6] というのは構文糖衣.
[3, 4, 5, 6]=⇒ 3 : (4 : (5 : (6 : [])))=⇒ 3 : 4 : 5 : 6 : []
ということで,リストを作っていきましょう!
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
リスト
.リスト型..
...... data List a = Empty | Cons a (List a)
レコード構文で書くと
data List a = Empty | Cons { listHead :: a
, listTail :: List a
}
Empty は []
Cons x xs は x : xs に対応する
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
リストの改善
.リスト型’..
......
infixr 5 : -:
data List a = Empty | a : -: (List a)
記号文字だけで値コンストラクタに出来る名前はコロン :から始めないといけない:: は使えないコロン :から始まる二項演算子は定義できない× x : + y = x + y,⃝ x + : y = x + yコロンは大文字として考える (@nushioさん)
infix, infixl, infixr で結合性を定めることが出来るデフォルトは infixl 9例) infixl 7 ∗, infixl 6 +,infixl 6 ‘xor‘,infixr 5 ‘Cons‘
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
リストの改善
.(++)..
......
infixr 5 ˆ++
(ˆ++) :: List a → List a → List a
Empty ˆ++ ys = ys
(x : -: xs) ˆ++ ys = x : -: (xs ˆ++ ys)
パターンマッチも使える!!
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
二分探索木
.二分探索木..
......
二分木
左の子 < 親 < 右の子
5
����3 7
����6 8
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
二分探索木
.二分探索木データ型........data Tree a = EmptyTree | Node a (Tree a) (Tree a)
簡単のため平衡木にはしません挿入,探索をする
treeInsert :: a → Tree a → Tree atreeElem :: a → Tree a → Bool
を実装していきます
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
7.8 型クラス 中級講座
Java や Python のような言語に出てくる「クラス」とは何の関係もありません.
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
クラス
.Eq型クラス..
......
class Eq a where
(==), (/ =) :: a → a → Bool
x == y = not (x / = y)
x / = y = not (x == y)
補足Eqは等値性を表すクラスですが,EQはOrdering型の値です.data Ordering = LT | EQ | GT
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
インスタンス宣言
.交通信号データ型を Eqのインスタンスに..
......
data TrafficLight = Red | Yellow | Greeninstance Eq TrafficLight where
Red == Red = True
Yellow == Yellow = True
Green == Green = True
== = False
(/ =)まで定義しなくて良い =⇒ 最小完全定義
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
インスタンス宣言
.Showのインスタンスに..
......
instance Show TrafficLight where
show Red = “Red light”
show Yellow = “Yellow light”
show Green = “Green light”
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
サブクラス化
.Num クラス........class (Eq a) ⇒ Num a where (以下省略)
Num は Eq のサブクラス
Eq は Num のスーパークラス
Num のインスタンスに出来るのは Eq クラスのものだけ
a を Num のインスタンスにしようと思うと Eq のインスタンスにしないといけない
(ちなみに GHC 7.4.1 で Eq を Num のスーパークラスにするという制約は取り除かれました.)
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
多相型を型クラスのインスタンスに
.問題..
......
Maybe を Eq のインスタンスにするにはどうすればいいか?
class Eq a where
(==), (/ =) :: a → a → Bool
x == y = not (x / = y)
x / = y = not (x == y)
Maybe は具体型ではないので,instance Eq Maybe where と出来ない.
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
多相型を型クラスのインスタンスに
.Maybeを Eqのインスタンスに..
......
instance Eq (Maybe a) where
Just x == Just y = x == y
Nothing == Nothing = True
/ = = False
Maybeは具体型ではないが,Maybe aは具体型.しかし,まだ1つ問題が残っています.a が Eq のインスタンスになっていないと x == y が使えない.
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
多相型を型クラスのインスタンスに
.Maybeを Eqのインスタンスに (完成版)..
......
instance (Eq a) ⇒ Eq (Maybe a) where
Just x == Just y = x == y
Nothing == Nothing = True
/ = = False
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
7.9 Yes と No の型クラス
if (0) alert(“YEAH!”) else alert(“No!”)
if (“”) alert(“YEAH!”) else alert(“No!”)
if (false) alert(“YEAH!”) else alert(“No!”)
JavaScriptではこのコードはすべて No! というアラートを表示しますが,真理値をBool型しか認めないHaskellではこういうことはできません.ここでは,Bool型でないものも真理値として使えるようなYesNo型 クラスを実装します.
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
YesNo型クラス
.YesNo型クラス..
......
class YesNo a where
yesno :: a → Bool
Int, [a], Bool, Maybe a, Tree a, TrafficLightを YesNo のインスタンスにします.
YesNo 用の ifっぽい関数 yesnoIf
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
Functor(関手)型クラス
.Functor 型クラス..
......
class Functor f where
fmap :: (a → b) → f a → f b
map :: (a → b) → [a] → [b]に似てるなぁ
f a が具体型なので,f は型引数を 1つもつ型コンストラクタ(クラスに出来るのは具体型だけではない)fmapは Functor則を満たさないといけない
fmap id = idfmap f . fmap g = fmap (f . g)
詳細は 11章
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
リスト Functor
.リストを Functorに..
......
instance Functor [] where
fmap = map
instance Functor [a] where ではない
[] は空リストではなくて [] aの []
fmap :: (a → b) → [] a → [] b
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
Maybe Functor
.Maybeを Functorに..
......
instance Functor Maybe where
fmap Nothing = Nothing
fmap f (Just a) = Just (f a)
instance Functor (Maybe a) where ではないfmap :: (a → b) → Maybe a → Maybe b
左のNothingはMaybe a型右のNothingはMaybe b型
fmap f (Just a) = Just (f a)
fmap x = x
は型エラー
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
Tree Functor
.Treeを Functorに..
......
data Tree a = EmptyTree | Node a (Tree a) (Tree a)
instance Functor Tree where
fmap EmptyTree = EmptyTree
fmap f (Node x left right)
= Node (f x) (fmap f left) (fmap f right)
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
Tree Functor
注意点
f が順序を保存するような関数でないと fmap したあとの木が二分探索木になっているとは限らない.例えば,Tree Intに対して fmap negateすると大小関係が入れ替わって「左の子<親<右の子」が成り立たなくなる.
二分木にはなっている.
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
Either Functor
.Eitherを Functorに..
......
instance Functor (Either a) where
fmap (Left x) = Left x
fmap f (Right y) = Right (f y)
型引数が複数ある時は部分適用させる
fmap :: (b → c) → Either a b → Either a c
よく使う方をRightにした方がよさそうですよね
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
読者への練習問題
.問題..
......
Data.Map も Functor にできます.どのように Functor のインスタンスになるでしょうか?
とりあえず,fmapの型は...fmap :: (a → b) → Map k a → Map k b
Hoogle にきいてみると...
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
種類
種類 (kind) : 型の型みたいなもの
: t は値の型を調べるコマンド
: k は型の種類を調べるコマンド
具体型は ∗Functorは ∗ → ∗
. . . . . .7.7 再帰的なデータ構造
. . . . . . . .7.8 型クラス 中級講座
. .7.9 Yes と No の型クラス
. . . . . . .7.10 Functor 型クラス
. .7.11 型を司るもの、種類
演習
Functorクラスのインスタンスにして下さい.
data Akari a = Waai a (Akari a) | Daisuki
data H oo gle = H oo oo oo oo oo gle
data Ha y oo = Ha y oo oo oo oo oo
data O b = OOOO|OOOOOO|O|OO
data Hom r a = Hom (r → a)
data State s a = State (s → (a, s))
data Just a = Nothing | Maybe (Maybe a)
ヒント
作るのはmap関数みたいなもの
とりあえず型を合わせる
fmap id が id になるように (Functor則の1つ)