State モナドにも挑戦してみようと思った。しかし、State モナドの型は次のようになる。
Prelude> :m Control.Monad.State Prelude Control.Monad.State> :info State newtype State s a = State {runState :: s -> (a, s)} -- Defined in Control.Monad.State.Lazy instance Monad (State s) -- Defined in Control.Monad.State.Lazy instance Functor (State s) -- Defined in Control.Monad.State.Lazy instance MonadFix (State s) -- Defined in Control.Monad.State.Lazy instance MonadState s (State s) -- Defined in Control.Monad.State.Lazy データコンストラクタ State のパラメータが {runState :: s -> (a,s)} だ。フィールド名 runState がついている上に、パラメータの型が s -> (a, s) だ。つまり引数が s で戻り値が (a, s) の「関数」だ。関数をパラメータにとるデータコンストラクタって何だ??? 仕方がないから、引数 s で戻り値 (a, s) の関数 \s -> ("hello", s) を作って、コンストラクタ State のパラメータにしてみた。 Prelude Control.Monad.State> let s = State (\s -> ("hello", s)) s の型はどうなっているだろうか。 Prelude Control.Monad.State> :t s s :: State s [Char] State 型だが、このままではどういう風に使うのか検討もつかない。しかし、State のコンテナにフィールド runState がついていたので、runState s は引数1個の関数になるはずだ。そこで、試してみた。 Prelude Control.Monad.State> runState s "world" Loading package syb-0.1.0.2 ... linking ... done. Loading package base-3.0.3.2 ... linking ... done. Loading package mtl-1.1.0.2 ... linking ... done. ("hello","world") 確かに関数として働かせることができた。\s -> ("hello", s) の s に "world" が代入されている。どうも、State 型のデータは、runState の引数にすると関数として働くようだ。こういうふうに自前で定義したState型のデータのほかに、State 型には、あらかじめ定義された、get という関数と put a という関数がある。それらの動作も確かめてみた。 Prelude Control.Monad.State> runState (get) "hello" ("hello","hello") Prelude Control.Monad.State> runState (put "world") "hello" ((),"world") get は一個の引数 s をとり、(s, s) を返し、put は二つの引数 a s をとり、((), a) を返す。注意しないといけないのは、get も put も runState でフィールド指定したときにのみ関数として働くことができる。 しかし、これのどこがモナドなのだろうか。そこで、思いついたのだが、get と put が >>= 結合できないかということだ。IO モナドの getLine と putStrLn からの類推だ。そこでやってみた。 Prelude Control.Monad.State> runState (get >>= put) "hello" ((),"hello") 確かに get が引数 "hello" を拾い上げ、put に渡して ((), "hello") と "hello" をタプルに入れて返している。 それでは、do 記法も使えるのだろうか。 Prelude Control.Monad.State> runState (do a <- get; put a) "hello" ((),"hello") 使えたようだ。それでは return も使えるだろうか。 Prelude Control.Monad.State> runState (return "hi" >>= put) "hello" ((),"hi") 使えた。どうやら、State モナドは runState の括弧の中で記述するようだ。 何がモナドなのかがなんとなく分かってきたので、最後に自前の State モナドを使ってget , put と連携させてみた。 Prelude Control.Monad.State> let s1 a = State (\s -> ("nice to meet you, " ++ a, s)) Prelude Control.Monad.State> runState (get >>= s1 >>= put) "world" ((),"nice to meet you, world") 何となく State モナドがモナドなんだという気がしてきた。結局 >>= で数珠繋ぎにできるのがモナドなのだろう。
by tnomura9
| 2011-11-05 18:50
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||