Stateモナド 単語

ステイトモナド

3.0千文字の記事
  • twitter
  • facebook
  • はてな
  • LINE

この記事はモナド(プログラミング)の一部として作成された内容を元にしています。

概要

Stateモナドも値を中に内包しているが、ちょっと変形された形で保管している。

状態 state から新しい状態 newState = p(state) と値xを作る関数、という形で保管している。

unit()flatMap()がどのような働きをするか検討すると多少は全貌が見えてくるのではないかと思う。

unitState()は後回しにして、どういう状態で保管しているかを述べる。

λ state → (x_1(state), p(state))
ただし、p(state)はstateを引数にし同じの違う値(正確には、同じとは限らない値)を返す関数。x_1(state)は、stateを引数とし、値xを作る関数

つまりStateモナドは関数の組(x_1, p)であると言うことができる。以降この形で表現する。

λ state → (_, p(state)) が、モデルで出てきた外の部分に相当する(Haskellではこの関数がStateモナドそのものではなくレコード(データ)の一つになっているが、実質的には同じことである)。

unit()

Stateモナドは x 以外に、λ state → (_, newState) の外の部分にも情報を保持している。つまり情報が増えるモナドなのである。x に対応するモナドunitState(x) 以外にも存在するということになる。

さてunitState()未定義だったが、外の部分に関する情報が存在しない以上、

unitState(x) = λ state1 → (x, state1) というstateの部分に変更を加えない関数(実際は単位元則で規定される)になる。

unitState(x) = (constantx, id)

ただし、constantx(state) = x という定数関数id(state) = state という恒等関数である。

よみがえる箱モデル

モデルは滅びぬ。何度でもよみがえるさ。2段にすれば説明できるだろうか。

HTMLではtableでレイアウトするなというけれど、divでは不本意にずれるのでtableで図示すると、

unitState(x) = constantx = λ state → x
id λ state → state

次に、flatMapState() の第二引数となる関数について述べる。

x から State y を作る関数だから

λ x → (λ state → (y, q(state)))
ただし、q(state)はstateを引数にし同じの違う値を返す関数

という高階関数である。つまりflatMapState()は(関数を戻り値とする)高階関数引数にとる高階関数である。

flatMap()

Stateモナドs = (s1, s2)

f(x) = (f1(x), f2(x))

とする。上述のように、s1, s2 はそれぞれ関数であるが、f1(x), f2(x) だけでなく f1(x), f2(x) 自体も関数になっているということである。すなわちstateに「関数」 f1(x) を適用して f1(x)(state) とすることができるということである。

flatMapState() の動作は、一言で言えば「状態を引き継ぎながら次の計算を行う」ことであるが、実際の動作は一言では言い表し難いものとなっている。

s `flatMapState` f の中身を式1本で書くと理解不能になること請け合いなので、順を追って説明する。

  • 「状態」stateが与えられているものとする。
  • stateに s1, s2 を適用して、s1(state), s2(state) を得る。
  • s1(state) に f を適用して、Stateモナド(f1(s1(state)), f2(s1(state)))を得る。
  • s2(state) は state と同じなので、f1(s1(state)), f2(s1(state)) をそれぞれ適用できる。
  • そうして得られた値が、 s `flatMapState` f に state を与えて得られる値である。

s `flatMapState` f = (s1, s2) `flatMapState` (f1, f2)

= (λ state → f1(s1(state))(s2(state)), λ state → f2(s1(state))(s2(state)))

なんじゃこりゃぁあ!!!

s f
state s1(state) f1(s1(state)) f1(s1(state))(s2(state))
s2(state) f2(s1(state)) f2(s1(state))(s2(state))
s `flatMapState` f

compose()

もうやめて!とっくに編集者ののライフはゼロよ! たぶん読者もね

ここで s `flatMapState` (f `composeState` g) について考えてみる。

s `flatMapState` f `flatMapState` g

s f g
state s1(state) f1(s1(state)) f1(s1(state))(s2(state)) g1(f1(s1(state))(s2(state))) g1(f1(s1(state))(s2(state)))(f2(s1(state))(s2(state)))
s2(state) f2(s1(state)) f2(s1(state))(s2(state)) g2(f1(s1(state))(s2(state))) g2(f1(s1(state))(s2(state)))(f2(s1(state))(s2(state)))
s `flatMapState` f `flatMapState` g

値でなく矢印を見る。

使いどころ

どのように使おうとも個人の自由なので、使いどころを書いたとしてもそれは書いた人の意見に過ぎないので誤りでないとは言い切れない。誤りを書いてしまうことを恐れてか、解説書などをはじめとして多くの場合で、動作を述べただけで説明が終わっているか、「状態付き計算を純にすることが出来ました」という教科書的表現にとどまっていることが多い。この記事はどうせ間違いだらけなので、読書感想文くらいのつもりで使いどころを書く。

関数型言語では、「状態」が結果(戻り値)にする場合は「状態」も引数に入ってくる。計算するたびに「状態」が更新される場合、純関数型言語では再代入が禁止されているので状態が更新されるたびに新しい変数名を割り当てる必要が生じ、名前空間圧迫する。

Stateモナドを用いると、変数名を割り当てずともStateに含まれた値として次の計算の引数に渡されるので、変数名の割り当てが不要になる。多分Stateモナドの効用は、更新される状態にいちいち変数名を割り当てずに済むということだけであり、それ以外の場面ではStateモナドを使用しなくても大差なく書くことができるはずである。

非純関数型言語では、Stateモナド内に相当する計算の間だけ、再代入可な局所変数を使用している状態に似ているといえる。イミュータブルを奨励する場合でも局所的に再代入可変数を使用することは、ミスの誘発が少ないとして許容することが多いような気がする

関連項目

この記事を編集する

掲示板

掲示板に書き込みがありません。

おすすめトレンド

ニコニ広告で宣伝された記事

記事と一緒に動画もおすすめ!
もっと見る

急上昇ワード改

最終更新:2024/04/24(水) 09:00

ほめられた記事

最終更新:2024/04/24(水) 09:00

ウォッチリストに追加しました!

すでにウォッチリストに
入っています。

OK

追加に失敗しました。

OK

追加にはログインが必要です。

           

ほめた!

すでにほめています。

すでにほめています。

ほめるを取消しました。

OK

ほめるに失敗しました。

OK

ほめるの取消しに失敗しました。

OK

ほめるにはログインが必要です。

タグ編集にはログインが必要です。

タグ編集には利用規約の同意が必要です。

TOP