fugafuga.write

日々のログ

すごいH本 part82

モナド

モナドは強化されたアプリカティブファンクターである。

モナドはある願いを叶えるための、アプリカティブ値の自然な拡張である。

願いとは、

普通の値 a を取って文脈付きの値を返す関数に、文脈付きの値 m a を渡したい

というもの。

言い換えると、a -> m b型の関数を、m a型の値に適用したい。ということ。

(>>=) :: (Monad m) => m a -> (a -> m b) -> m b

つまり、この関数が使いたい。

関数>>=バインド(bind)と呼ばれる。

文脈付きの値を普通の値をとる関数に入力するのにはどうしたらいいのか? これがモナドの一番の関心事である。

Maybe から始めるモナド

Maybe a 型の値は a 型の値を表しているが、失敗する可能性があるという文脈がついている。

ファンクター値としての Maybe に対して fmap すると以下のようになる。

*Main Lib> fmap (++"!") (Just "wisdom")
Just "wisdom!"
*Main Lib> fmap (++"!") Nothing
Nothing

アプリカティブファンクターとしての Maybe の機能も似たようなもの。 しかし、値だけでなく、適用する関数のほうにも文脈が付く。

*Main Lib> Just (+3) <*> Just 5
Just 8
*Main Lib> Nothing <*> Just "greed"
Nothing

Maybe にとっての >>= をどう定義するのか。

*Main Lib> (\x -> Just (x+1)) 1
Just 2
*Main Lib> (\x -> Just (x+1)) 100
Just 101

数をとり、それに1を足して Just で包む。1 を入力して、Just 2 に評価されている。 この関数に Maybe 値を入力するにはどうしたらよいか考える。

これは、Maybe がアプリカティブファンクターとしての振る舞いができることから、 Just 値が来たときは、Just の中身を取り出し、それを関数に渡す。 Nothing が来た時は、結果として Nothing を返す。

>>=applyMaybe という関数で実装してみる

applyMaybe :: Maybe a -> (a -> Maybe b) -> Maybe b
applyMaybe Nothing f = Nothing
applyMaybe (Just x) f = f x

実行

*Main> Just 3 `applyMaybe` \x -> Just (x+1)
Just 4
*Main> Just "smile" `applyMaybe` \x -> Just (x ++ " :)")
Just "smile :)"
*Main> Nothing `applyMaybe` \x -> Just (x+1)
Nothing
*Main> Nothing `applyMaybe` \x -> Just (x ++ " :)")
Nothing

関数の結果が Nothing の場合

*Main> Just 3 `applyMaybe` \x -> if x > 2 then Just x else Nothing
Just 3
*Main> Just 1 `applyMaybe` \x -> if x > 2 then Just x else Nothing
Nothing

文脈付きの値を普通の値を引数にとる関数に渡すことができている。

Monad 型クラス

class Monad m where
    return :: a -> m a

    (>>=) :: m a -> (a -> m b) -> m b

    (>>) :: m a -> m b -> m b
    x >> y = x >>= \_ -> y

    fail :: String -> m a
    fail msg = error msg

return は Applicative 型クラスの pure と同じで、 値を取って、その値を再現できるような最小のデフォルト文脈に入れる。

>>= はバインド。通常の値を取り、モナド値を返す関数を適用して、モナド値を返す。

>> はデフォルト実装があるので省く。(詳細はあとで見る)

fail はユーザーがコードの中から fail を呼び出すことはなく、 Haskell システムが呼び出す。 fail はモナド用の特別な構文において、パターンマッチに失敗してもプログラムを異常終了させず、 失敗をモナドの文脈の中で扱えるようにするためのもの。

Maybe の Monad インスタンスの実装をみてゆく

instance Monad Maybe where
    return x = Just x
    Nothing >>= f = Nothing
    Just x >>= f = f x
    fail _ = Nothing

モナド化したMaybeを見る

*Main> return "hohohoho" :: Maybe String
Just "hohohoho"
*Main> Just 9 >>= \x -> return (x*10)
Just 90
*Main> Nothing >>= \x -> return (x*10)
Nothing

所感

これがモナドか。 いまのところよくわからん。

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

  • 作者: MiranLipovaca
  • 出版社/メーカー: オーム社
  • 発売日: 2017/07/14
  • メディア: Kindle版
  • 購入: 4人 クリック: 9回
  • この商品を含むブログを見る