Endo
遠藤さんではない。自分自身に返る射を持つ圏のこと。
ドメインとコドメインが同一の対象の射を自己準同型射 (endomorphism) と呼ぶ。
http://nineties.github.io/category-seminar/2.html
実例
-- Endoの実例 import Data.Monoid import Data.Foldable main = do -- 左から順番に計算していく。 print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,33] ) 0 print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,32] ) 0 print $ appEndo( foldMap (\x -> if even x then Endo (x *) else Endo(+ x)) [1,12,3,34,34] ) 0 print $ ((((33*)34+)3*)12+1)
おさらい
P281-P290まで
- 「モナド」は「アプリカティブファンクター」の強化版(アプリカティブファンクターはファンクターの強化版) どんどん柔軟性が高まる(三兄弟)
- Maybeに特化したモナドの説明
- Monad型クラス
Prelude> return "WHAT" :: Maybe String Just "WHAT" Prelude>
- ピエールの綱渡り(このネタは独習Scalazにも出てくる)
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Pole landLeft n (left, right) = (left + n, right) landRight :: Birds -> Pole -> Pole landRight n (left, right) = (left, right + n) -- バランス棒 x -: f = f x main = do print $ landLeft 2 (0, 0) print $ landLeft 1 (1, 2) print $ landRight (-1) (1, 2) print $ (0, 0) -: landLeft 1 -: landRight 1 -: landLeft 2
F#にあったものを流用したのが(&) らしい。
Prelude> Prelude.sum $ filter even $ map (+3) [1,2,3] 10
が、こういう書き方が出来るようになるらしい(GHC 7.10の場合)
Prelude> [1,2,3] & map (+3) & filter even & Prelude.sum
落ちるぅうあああ
4羽来た瞬間に落ちるパターンを実装する。具体的には、JustとNothingを使う。
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Maybe Pole landLeft n (left, right) | abs ((left + n) - right) < 4 = Just (left + n, right) | otherwise = Nothing landRight :: Birds -> Pole -> Maybe Pole landRight n (left, right) | abs (left - (right + n)) < 4 = Just (left, right + n) | otherwise = Nothing -- バランス棒 x -: f = f x main = do print $ landLeft 2 (0, 0) print $ landLeft 1 (1, 2) print $ landRight (-1) (1, 2) print $ landRight 10 (0, 3)
でもこういう書き方はできなくなった。
(0, 0) -: landLeft 1 -: landRight 1 -: landLeft 2
なので、実行方法も合わせる必要がある
*Main> :t (landRight 3 >>=) (landRight 3 >>=) :: (Maybe Pole -> Pole -> b) -> Pole -> b
ピエールの綱渡り 複数の手順の方法
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Maybe Pole landLeft n (left, right) | abs ((left + n) - right) < 4 = Just (left + n, right) | otherwise = Nothing landRight :: Birds -> Pole -> Maybe Pole landRight n (left, right) | abs (left - (right + n)) < 4 = Just (left, right + n) | otherwise = Nothing -- バランス棒 x -: f = f x main = do print $ landLeft 2 (0, 0) print $ landLeft 1 (1, 2) print $ landRight (-1) (1, 2) print $ landRight 10 (0, 3) print $ landRight 1 (0, 0) >>= landLeft 2 -- NothingがまじるとずっとNothing print $ Nothing >>= landLeft 2 -- print $ (0, 0) -: landLeft 1 -: landRight 4 -: landLeft (-1) -: landRight (-2) -- の代わりの書き方 -- returnは必須 print $ return (0, 0) >>= landRight 2 >>= landLeft 2 >>= landRight 2 -- ラムダを使った書き方 print $ return (0, 0) >>= (\x -> landRight 2 x) >>= (\x -> landLeft 2 x) >>= (\x -> landRight 2 x)
アプリカティブとの比較
(+) <$> Just 3 <*> Just 4
アプリカティブだと、こういう書き方が出来ない
(+) <$> Nothing <*> Just 4 <*> Just 4
return (0,0) >>= landLeft 2 >>= landRight 2 >>= landRight 1
演算をどんどんつなげていくことができる。
バナナ
途中でバナナを踏んだら即死するデータ型を作る。 本にはないけど、ついでに、豆腐を踏んだらスタート地点にもどるやつも実装してみる
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Maybe Pole landLeft n (left, right) | abs ((left + n) - right) < 4 = Just (left + n, right) | otherwise = Nothing landRight :: Birds -> Pole -> Maybe Pole landRight n (left, right) | abs (left - (right + n)) < 4 = Just (left, right + n) | otherwise = Nothing -- バランス棒 x -: f = f x -- バナナ banana :: Pole -> Maybe Pole banana _ = Nothing -- 豆腐 tofu :: Pole -> Maybe Pole tofu _ = Just (0,0) main = do print $ landLeft 2 (0, 0) print $ landLeft 1 (1, 2) print $ landRight (-1) (1, 2) print $ landRight 10 (0, 3) print $ landRight 1 (0, 0) >>= landLeft 2 -- NothingがまじるとずっとNothing print $ Nothing >>= landLeft 2 -- print $ (0, 0) -: landLeft 1 -: landRight 4 -: landLeft (-1) -: landRight (-2) -- の代わりの書き方 -- returnは必須 print $ return (0, 0) >>= landRight 2 >>= landLeft 2 >>= landRight 2 -- ラムダを使った書き方 print $ return (0, 0) >>= (\x -> landRight 2 x) >>= (\x -> landLeft 2 x) >>= (\x -> landRight 2 x) print $ (landRight 3 (1,2) >>= (\x -> landLeft 3 x)) print $ landRight 3 (1, 2) -- バナナと豆腐 print $ return (0, 0) >>= landLeft 1 >>= banana >>= landRight 1 print $ return (0, 0) >>= landLeft 1 >>= tofu >>= landRight 1 print $ return (0, 0) >>= landLeft 1 >>= landRight 1 >>= tofu
モナドを使わない選択
-- モナドを使わない選択 routine :: Maybe Pole routine = case landLeft 1 (0, 0) of Nothing -> Nothing Just pole1 -> case landRight 4 pole1 of Nothing -> Nothing Just pole2 -> case landLeft 2 pole2 of Nothing -> Nothing Just pole3 -> landLeft 1 pole3
こういうふうに書かないといけないので、ネストの嵐になってむっちゃめんどう。
13.5 do記法
main = do print $ Just 3 >>= ( \ x -> Just (show x ++ "!")) print $ Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Just (show x ++ y))) -- print $ Nothing >>= ( \ x -> Just "!" >>= ( \ y -> Just (show x ++ y))) -- print $ Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Nothing)) -- Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Nothing))
-- モナド値を連鎖させた式と等価なものを、ずっと簡潔に表せる記法が do 式 -- doを使わない書き方 foo1 :: Maybe String foo1 = Just 3 >>= ( \ x -> Just "!" >>= ( \ y -> Just (show x ++ y))) -- doを使った書き方 foo2 :: Maybe String foo2 = do x <- Just 3 y <- Just "!" Just (show x ++ y) main = do print $ foo1 print $ foo2
なんとなくわかるけど、自分流にコードをアレンジするの難しいね。
- 作者: Miran Lipovača,田中英行,村主崇行
- 出版社/メーカー: オーム社
- 発売日: 2012/05/23
- メディア: 単行本(ソフトカバー)
- 購入: 25人 クリック: 580回
- この商品を含むブログ (69件) を見る