readhbon.doorkeeper.jp
Endo
遠藤さんではない。自分自身に返る射を持つ圏のこと。
Data.Monoid
nineties.github.io
独習 Scalaz — 圏論
ドメインとコドメインが同一の対象の射を自己準同型射 (endomorphism) と呼ぶ。
http://nineties.github.io/category-seminar/2.html
実例
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
Data.Function
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
print $ Nothing >>= landLeft 2
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
print $ Nothing >>= landLeft 2
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)))
foo1 :: Maybe String
foo1 = Just 3
>>= ( \ x ->
Just "!" >>= ( \ y ->
Just (show x ++ y)))
foo2 :: Maybe String
foo2 = do
x <- Just 3
y <- Just "!"
Just (show x ++ y)
main = do
print $ foo1
print $ foo2
なんとなくわかるけど、自分流にコードをアレンジするの難しいね。