あどけない話

インターネットに関する技術的な話など

例題で比較する状態系のモナド

金曜日に状態系のモナドを説明しないといけないので、例題を書いて比較できるようにしておきます。

呪文として、以下のモジュールを読み込んでおきましょう。

import Data.Char
import Control.Monad.Identity
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.State

Identityモナド

入力が一つで、出力が一つのモナド。面白みはない。

i :: Identity Int
i = do x <- return 2
       y <- return 3
       return $ x * y

でも、モナドHaskell の中に住むマイクロ言語で、このマイクロ言語でマイクロプログラムを作成した後は、run で実行するものだというイメージは分かるかも。

> runIdentity i
→ 6

Readerモナド

入力が二つで、出力が一つのモナド。入力の一方が、read only の状態。この状態は、マイクロプログラムを実行する際に環境として与えられ、ask で取り出せる。

r :: Reader Char Int
r = do x <- ask
       y <- return 3
       return $ digitToInt x * y

環境 '2'を与えて走らせてみる。(マイクロプログラムにとって、環境とはグローバル変数だと考えてよい。)

> runReader r '2'6

Writer モナド

入力が一つで、出力が二つのモナド。出力の一方が、ログとなる。ログは tell で書き足せる。

w :: Writer String Int
w = do x <- return 2
       tell [intToDigit x, ':']
       y <- return 3
       tell [intToDigit y, ':']
       return $ x * y

走らせてみると、ログが取れているのが分かる。

> runWriter w
→ (6,"2:3:")

Stateモナド

入力が二つで、出力が二つのモナド。入力と出力の一方が状態を表す。状態の初期値は、マイクロプログラムを実行する際に環境として与えられ、get で取り出せる。また、put で変更できる。

s :: State Char Int
s = do x <- get
       put '3'
       y <- get
       return $ digitToInt x * digitToInt y

初期状態 '2' を与えて走らせるとこうなる。

> runState s '2'
→ (6,'3')