Haskell超初心者勉強会 14
すごいHaskell 第12章: モノイド (前編)
今回の内容
•newtype
•Monoid とは
•いろんな Monoid
Monoid ...?
•「二項演算子で結合できるような型」
でもその前に、、
newtype
•「1つの型を取り、それを何かにくるん
で別の型にみせかけたい」
data ZipList a = ZipList { getZipList :: [a] }
newtype ZipList a = ZipList { getZipList :: [a] }
newtype の利点・欠点
• 利点
• 速い。包んだり戻したりの処理を省略。
• 欠点
• 値コンストラクタが1種類だけ
• 値コンストラクタがとれるフィールドが
ひとつだけ
newtypeでの
型クラス導出(deriving)
•deriving で導出出来る
•くるまれている型が導出しようとして
いる型クラスのインスタンスでなけれ
ばならない
newtypeでの
型クラスのインスタンス作成
• タプルをFunctorにしたい
• fmap では f を第一要素に効かせたい
• タプルは型コンストラクタが2つ型を取る
• 1つだけ指定できない (関数は出来たのに)
• newtype で包む
newtype Pair b a = Pair { getPair :: (a, b) }
instance Functor (Pair c) where
fmap f (Pair (x, y)) = Pair (f x, y)
こんな感じ
newtype Pair b a = Pair { getPair :: (a, b) }
instance Functor (Pair c) where
fmap f (Pair (x, y)) = Pair (f x, y)
> getPair $ fmap (*100) (Pair (2, 3))
(200,3)
> getPair $ fmap reverse (Pair (“london”, 3))
("nodnol",3)
newtypeの
パターンマッチ (1)
data CoolBool = CoolBool { getCoolBool :: Bool }
helloMe :: CoolBool -> String
helloMe (CoolBool _) = "Hello"
main = putStrLn $ helloMe undefined
評価するとエラーになる値
ここでエラーが起きる
newtypeの
パターンマッチ (2)
newtype CoolBool = CoolBool {getCoolBool :: Bool}
helloMe :: CoolBool -> String
helloMe (CoolBool _) = "Hello"
main = putStrLn $ helloMe undefined
エラーにならない!
値コンストラクタが1つしか存在しな
いので引数を評価せずマッチできる
type, newtype, dataの
整理
•type -- 型の別名 (実際は同じ型)
•newtype -- 包んだ別の型を作る。値コ
ンストラクタは1つだけ。フィールド1
つだけ。速い。
•data -- 新しい型を作る
type, newtype, dataの
使い所
•type -- 型シグネチャを整理したい。名
が体を表すようにしたい。
•newtype -- 既存型をある型クラスのイ
ンスタンスにしたい。新しい型に包み
たい。
•data -- 新しい型を作りたい
余談: Scala 2.10 で
導入された value class
• 1つの値をwrapする
• コンパイル時は違う型
• 基本的に実行時は型変換されない
• pattern match とかしようとすると
実行時に型変換される
class Wrapper(val underlying: Int)
extends AnyVal {
def foo: Wrapper = new Wrapper(underlying * 19)
}
○ ○ = ○
• (* と 1)、(++ と []) に共通の性質は?
• 関数は引数を2つとる
• 2引数と戻り値の型は等しい
• 相手を変えない特別な値がある(1, [])
• 結合的である (a * b) * c = a * (b * c)
→これが Monoid
Monoid とは
•結合的な二項演算子 と 単位元
•* と 1
•++ と []
•+ と 0
•他にも無数の Monoid
Monoid 型クラス
class Monoid m where
mempty :: m
mappend :: m -> m -> m
mconcat :: [m] -> m
mconcat = foldr mappend mempty
mは具体型
単位元(多相定数)
関数
Monoid則
•プログラマの責任!
1) mempty `mappend` x = x
2) x `mappend` mempty = x
3) (x `mappend` y) `mappend` z =
x `mappend` (y `mappend` z)
ここからいろんな
Monoid を見ていきます
ListはMonoid
x `mappend` y = y `mappend` x
は満たさなくて良い
instance Monoid [a] where
mempty = []
mappend = (++)
Monoid [] ではないことに注意
数をMonoidに
instance Num a => Monoid a where
mempty = 1
mappend = (*)
instance Num a => Monoid a where
mempty = 0
mappend = (+)
でも、こっちも定義したい
いったいどうしたら…
そこで newtype
newtype Product a =
Product { getProduct :: a }
deriving (Eq,Ord,Read,Show,Bounded)
instance Num a => Monoid (Product a) where
mempty = Product 1
Product x `mappend` Product y =
Product (x * y)
> getProduct $ Product 3 `mappend` Product 9
27
Sum も同じように定義されている
AnyとAll
•Boolに対するMonoid
newtype Any =
Any { getAny :: Bool }
deriving (Eq,Ord,Read,Show,Bounded)
instance Monoid Any where
mempty = Any False
Any x `mappend` Any y =
Any (x || y)
Ordering monoid
•Ordering 型。値は LT, EQ, GT
instance Monoid Ordering where
mempty = EQ
LT `mappend` _ = LT
EQ `mappend` y = y
GT `mappend` _ = GT
左優先。ただし左がEQの時は右。
文字列の辞書順と合わせた定義。
長さ比較、
同じ時は辞書順比較
import Data.Monoid
lengthCompare :: String -> String -> Ordering
lengthCompare x y =
(length x `compare` length y)
`mappend` (x `compare` y)
便利!
ほんとに便利...?
Maybe monoid
instance Monoid a => Monoid (Maybe a) where
mempty = Nothing
Nothing `mappend` m = m
m `mappend` Nothing = m
Just m1 `mappend` Just m2 =
Just (m1 `mappend` m2)
中身が Monoid の場合はこんな定義ができる
Maybe monoid
First
newtype First a = First {getFirst :: Maybe a}
deriving (Eq,Ord,Read,Show)
instance Monoid (First a) where
mempty = First Nothing
First (Just x) `mappend` _ = First (Just x)
First Nothing `mappend` x = x
> getFirst . mconcat . map First $
[Nothing, Just 9, Just 10]
Just 9
同様に Last a も定義されている
今日はここまで
•今回の感想:
Monoidにすると何がうれしいのかな?
•次回はMonoidでの畳み込みです。
おたのしみに!
これも面白そう
•独習 Scalaz http://goo.gl/8sXTD7
•

Haskell超初心者勉強会14