私はついにモナドの使い方を理解しました(私がそれらを理解しているかどうかはわかりません...)が、私のコードは決して非常にエレガントではありません。Control.Monad
これらすべての機能が実際にどのように役立つかについての理解が不足しているためだと思います。したがって、状態モナドを使用して、特定のコードでこれに関するヒントを求めるのがよいと思いました。
このコードの目的は、さまざまな種類のランダムウォークを計算することです。これは、より複雑なものの前に私がやろうとしていることです。問題は、同時に2つのステートフル計算があり、それらを優雅に構成する方法を知りたいということです。
- 乱数発生器を更新する関数は、ある種のものです。
Seed -> (DeltaPosition, Seed)
- ランダムウォーカーの位置を更新する関数は、ある種のタイプです
DeltaPosition -> Position -> (Log, Position)
(Log
ランダムウォーカーの現在の位置を報告するための何らかの方法があります)。
私がやったことはこれです:
この2つのステートフル計算を構成する関数があります。
composing :: (g -> (b, g)) -> (b -> s -> (v,s)) -> (s,g) -> (v, (s, g))
composing generate update (st1, gen1) = let (rnd, gen2) = generate gen1
(val, st2) = update rnd st1
in (val, (st2, gen2))
次に、それを状態を構成する関数に変換します。
stateComposed :: State g b -> (b -> State s v) -> State (s,g) v
stateComposed rndmizer updater = let generate = runState rndmizer
update x = runState $ updater x
in State $ composing generate update
そして、私は最も単純なものを持っています。たとえば、現在の位置に乱数を合計するだけのランダムウォーカーです。
update :: Double -> State Double Double
update x = State (\y -> let z = x+y
in (z,z))
generate :: State StdGen Double
generate = State random
rolling1 = stateComposed generate update
そしてこれを繰り返し行う関数:
rollingN 1 = liftM (:[]) rolling1
rollingN n = liftM2 (:) rolling1 rollings
where rollings = rollingN (n-1)
そして、これをロードしghci
て実行すると、次のようになります。
*Main> evalState (rollingN 5) (0,mkStdGen 0)
[0.9872770354820595,0.9882724161698186,1.9620425108498993,2.0923229488759123,2.296045158010918]
ランダムウォーカーが占める位置のリストである、私が欲しいものを手に入れます。しかし...これを行うにはもっとエレガントな方法があるに違いないと思います。2つの質問があります:
の巧妙な関数を使用して、これらの関数をより「モナディック」な方法で書き直すことはできます
Control.Monad
か?このような状態の組み合わせで使用できる一般的なパターンはありますか?これはモナド変換子などと関係がありますか?