(前編のおさらい)
新しいデータ型を定義する
data 型名 =値コンストラクタ
data Bool = False | True
data Shape = Circle Float Float Float |
Rectangle Float Float Float Float
data Point = Point Float Float
5.
(前編のおさらい)
レコード構文
data Person =Person { firstName :: String
, lastName :: String
, age :: Int
, height :: Float
, phoneNumber :: String
, flavor :: String }
6.
(前編のおさらい)
型引数
data 型コンストラクタ =値コンストラクタ
(型名 型引数)
data Maybe a = Nothing | Just a
data Either a b = Left a | Right b
-- 3次元ベクトルの例
data Vector a = Vector a a a
(前編のおさらい)
型シノニム
type String =[Char]
type Name = String
type PhoneNumber = String
type PhoneBook = [(Name, PhoneNumber)]
-- 以下の例では AssocList は型コンストラクタ
type AssocList k v = [(k, v)]
例:独自リスト型
data List a= Empty
| Cons a (List a)
deriving (Show, Read, Eq, Ord)
-- レコード構文の場合
data List a = Empty
| Cons { listhead :: a
, listtail :: List a }
deriving (Show, Read, Eq, Ord)
例:独自リスト型の結合
infixr 5 ^++
(^++):: List a -> List a -> List a
Empty ^++ ys = ys
(x :-: xs) ^++ ys = x :-: (xs ^++ ys)
4 実はパターンマッチとは、値コンストラクタのマッチ
4 標準の : も値コンストラクタ
17.
別の例:二分探索木
data Tree a= EmptyTree
| Node a (Tree a) (Tree a)
deriving (Show)
4 二分探索木:各要素について、
4 左部分木の全要素がその要素より小さい
4 右部分木の全要素がその要素より大きい
18.
木に要素を追加する関数
4 与えられた木の直接更新は不可、新しい木を作って返す
singleton ::a -> Tree a
singleton x = Node x EmptyTree EmptyTree
treeInsert :: (Ord a) => a -> Tree a -> Tree a
treeInsert x EmptyTree = singleton x
treeInsert x (Node y left right)
| x == y = Node y left right -- 同じなら挿入しない
| x < y = Node y (treeInsert x left) right
| x > y = Node y left (treeInsert x right)
木に要素が属するか調べる関数
treeElem :: (Orda) => a -> Tree a -> Bool
treeElem x EmptyTree = False
treeElem x (Node y left right)
| x == y = True
| x < y = treeElem x left
| x > y = treeElem x right
Eq 型クラスの宣言
class Eqa where
(==) :: a -> a -> Bool
(/=) :: a -> a -> Bool
x == y = not (x /= y)
x /= y = not (x == y)
4 a は型引数で、Eq のインスタンスとなる型
24.
Eq 型クラスのインスタンス宣言
data TrafficLight= Red | Yellow | Green
instance Eq TrafficLight where
Red == Red = True
Yellow == Yellow = True
Green == Green = True
_ == _ = False
4 注意:通常は deriving で自動導出する
25.
最小完全定義
x == y= not (x /= y)
x /= y = not (x == y)
4 Eq のインスタンスは == か /= のどちらかを定義する必要が
ある
4 片方を定義(デフォルト実装を上書き)すれば、もう片方
も定義される
Maybe を Eqのインスタンスにす
る?
class Eq a where
(==) :: a -> a -> Bool
4 型引数 a は具体型でなくてはダメ(関数定義にあわない)
4 Maybe は具体型でなく多相型(型コンストラクタ)
4 じゃあ具体型 Maybe Char を Eq のインスタンスにする?
4 それでは Maybe Int は? ・・・きりがない
インスタンス宣言に型クラス制約を
つける
4 型 mが Eq 型クラスでないとダメ
4 型クラス制約をつける
instance (Eq m) => Eq (Maybe m) where
Just x == Just y = x == y
Nothing == Nothing = True
_ == _ = False
31.
再度整理してみる
4 Eq 型クラス宣言では、aが具体型でないとダメ
4 (==) :: a -> a -> Bool と使われるから
4 a に Maybe は渡せない
4 (==) :: Maybe -> Maybe -> Bool はダメ
4 a に Maybe m なら渡せる
4 (==) :: (Eq m) => Maybe m -> Maybe m -> Bool
Functor 型クラス
class Functorf where
fmap :: (a -> b) -> f a -> f b
4 この f は具体型ではなく、型コンストラクタ
4 引数1 : 型 a から型 b への関数型
4 引数2 : 型コンストラクタ f に型引数 a を適用した型
4 戻り値 : 型コンストラクタ f に型引数 b を適用した型
41.
リストの map
-- リストのmap
map :: (a -> b) -> [a] -> [b]
-- Functor の fmap
fmap :: (a -> b) -> f a -> f b
4 map はリスト限定で動作する fmap だといえる
Maybe の Functorインスタンス宣言
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap f Nothing = Nothing
4 Maybe は型コンストラクタ
44.
二分探索木の Functor インスタンス
宣言
instanceFunctor Tree where
fmap f EmptyTree = EmptyTree
fmap f (Node x left right)
= Node (f x) (fmap f left) (fmap f right)
4 Tree は型コンストラクタ(Tree a が具体型)
4 注意:任意の関数を適用した後は二分探索木の性質を保た
ない
45.
Either の場合は?
4 Eitherは型引数を 2 つとる型コンストラクタ
4 Either a b が具体型
4 1 つだけ部分適用すると Functor にできる
4 Either a は型引数を 1 つとる型コンストラクタ
46.
Either の Functorインスタンス宣言
instance Functor (Either a) where
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x
4 data Either a b = Left a | Right b
4 Left と Right で型が違うことに注意
4 fmap で適用する関数 f は b -> c 型
4 Right 側には適用できるが、Left 側には適用できない