読者です 読者をやめる 読者になる 読者になる

by shigemk2

当面は技術的なことしか書かない

第2期 第20回 H本読書会 in 秋葉原 #readhbon

Haskell

readhbon.doorkeeper.jp

前回はモノイド。今回はモナドです。

  • 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

d.hatena.ne.jp

今回。モナド。

  • アプリカティブファンクターは強化されたファンクター。モナドは強化されたアプリカティブファンクター。という意味合い。
  • アプリカティブ値は文脈の付加された値。
  • モナドは >>= をサポートするアプリカティブファンクターにすぎません(!)
  • 単に関数を値に適用すればよろしい。ところが、特定の文脈が付きまとう値を扱うとなると、その変な値を関数に食わせるとどうなるのか、文脈を 保つにはどうするのか、ちゃんと考えないといけません
  • 函の中の値を扱う。適用する。には、どうしたらよいのか。

www.shigemk2.com

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で実装してみる。

gist.github.com

長いのでここまで

モナドの可換。図が狂ってる。

モナド (圏論) - Wikipedia

自己関手の圏 is 何

south37.hatenablog.com

結合則があり、単位元があればモノイド。モノイド対象はモノイドと言い換えても良い。

モナドはモノイドの一種。。

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

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