前回はモノイド。今回はモナドです。
- Monoid 型クラス
- mempty
- mappend
- mconcat
- モノイド則
- Haskell的にはmempty
mappend
x = xなど - モノイドとの遭遇(実際に何がモノイドなのか)
- リスト
- ProductとSum
- AnyとAll
- Ordering(LTとかEQとか)
- Maybe
Prelude Data.Monoid> [1,2,3] `mappend` [4,5,6] [1,2,3,4,5,6] Prelude Data.Monoid> getFirst $ First (Just 'a') `mappend` First (Just 'b') Just 'a'
import Data.Monoid import qualified Data.Foldable as F data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show) instance F.Foldable Tree where foldMap f EmptyTree = mempty foldMap f (Node x l r) = F.foldMap f l `mappend` f x `mappend` F.foldMap f r testTree = Node 5 (Node 3 (Node 1 EmptyTree EmptyTree) (Node 6 EmptyTree EmptyTree) ) (Node 9 (Node 8 EmptyTree EmptyTree) (Node 10 EmptyTree EmptyTree) ) main = do print $ F.foldr (+) 0 testTree print $ F.foldl (*) 1 testTree print $ getAny $ F.foldMap ( \ x -> Any $ x == 3) testTree print $ getAny $ F.foldMap ( \ x -> Any $ x > 15) testTree print $ F.foldMap ( \ x -> [x]) testTree
モノイド
独習Scalaz
今回。モナド。
- アプリカティブファンクターは強化されたファンクター。モナドは強化されたアプリカティブファンクター。という意味合い。
- アプリカティブ値は文脈の付加された値。
- モナドは >>= をサポートするアプリカティブファンクターにすぎません(!)
- 単に関数を値に適用すればよろしい。ところが、特定の文脈が付きまとう値を扱うとなると、その変な値を関数に食わせるとどうなるのか、文脈を 保つにはどうするのか、ちゃんと考えないといけません
- 函の中の値を扱う。適用する。には、どうしたらよいのか。
fmap :: (a -> b) -> f a -> f -- ファンクター (<*>) :: f (a -> b) -> f a -> f b -- アプリカティブファンクター (>>=) :: m a -> (a -> m b) -> m b -- モナド
13.2 モナドとしてのMaybe
- アプリカティブファンクターの知識を踏まえ、深めていくことだけがモナドの奥義に至る道
- ファンクターは、値に文脈が付く
- アプリカティブファンクターになると、値だけでなく、値に適用する関数のほうにも文脈が付く
Prelude Data.Monoid Control.Applicative> Just (+3) <*> Just 3 Just 6 Prelude Data.Monoid Control.Applicative> Nothing <*> Just "greed" Nothing
アプリカティブファンクターの例。
Prelude Data.Monoid Control.Applicative> ( \ x -> Just (x+1)) 1 Just 2
では、引数がMaybe値だったらどうするの?それを解決する答えが、モナドにある。
以下、オレオレバインド(>>=)の実装。 gist.github.com
引数は無名関数。
- モナドって便利なのか?
- モナドにはできてアプリカティブファンクターにはできないこともある
13.3 Monad 型クラス
Prelude> :i Monad class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a -- Defined in `GHC.Base' instance Monad Maybe -- Defined in `Data.Maybe' instance Monad (Either e) -- Defined in `Data.Either' instance Monad [] -- Defined in `GHC.Base' instance Monad IO -- Defined in `GHC.Base' instance Monad ((->) r) -- Defined in `GHC.Base'
Haskellのreturnは、値を文脈に入れて返すもので、他の言語のように関数の実行を中断させる命令ではない。
Prelude Control.Applicative Data.Monoid> :i >> class Monad m where ... (>>) :: m a -> m b -> m b ... -- Defined in `GHC.Base' infixl 1 >>
ロープ上のバナナは後述。
文脈を持った値を引数にとり、中身に関数を適用して文脈を持った値をそのまま返す例。
- ふつうのパターンマッチより優れているのではないか、という事例。
Prelude Control.Applicative Data.Monoid> Just 9 >>= \x -> return (x*10) Just 90 Prelude Control.Applicative Data.Monoid> Nothing >>= \x -> return (x*10) Nothing Prelude Control.Applicative Data.Monoid> return "WHAT" "WHAT" Prelude Control.Applicative Data.Monoid> return "WHAT" :: Maybe String Just "WHAT" Prelude Control.Applicative Data.Monoid> let (Just x) = Just 3 Prelude Control.Applicative Data.Monoid> x Prelude Control.Applicative Data.Monoid> let (Just x) = Nothing Prelude Control.Applicative Data.Monoid> x *** Exception: <interactive>:14:5-22: Irrefutable pattern failed for pattern (Data.Maybe.Just x) Prelude Control.Applicative Data.Monoid> Just 3 >> Just 4 Just 4 Prelude Control.Applicative Data.Monoid> Just 3 >> Nothing Nothing
putStrLnのはなし。値を取り出して、適用する。なお、putStrLnには戻り値がない。標準出力はその副作用。
Prelude Control.Applicative Data.Monoid> putStrLn "aaa" >>= \x -> return x aaa Prelude Control.Applicative Data.Monoid> putStrLn "aaa" aaa Prelude Control.Applicative Data.Monoid> :t putStrLn putStrLn :: String -> IO ()
13.4 綱渡り
ピエールの綱渡り。独習Scalazにもちょくちょく出てくる。
中野さん(仮)はバランス棒を持ちながら綱渡りをしているのだが、時たま鳥が棒の上で一休みすることがあり、鳥が棒の片サイドに集中して一休みすると中野さん(仮)はバランスを崩して転落してしまう。
このピエールの綱渡りをHaskellで実装してみる。
長いのでここまで
モナドの可換。図が狂ってる。
自己関手の圏 is 何
結合則があり、単位元があればモノイド。モノイド対象はモノイドと言い換えても良い。
モナドはモノイドの一種。。
- 作者: Miran Lipovaca
- 出版社/メーカー: オーム社
- 発売日: 2012/09/21
- メディア: Kindle版
- 購入: 4人 クリック: 9回
- この商品を含むブログを見る