我終於忍住瞭如何使用monads(不知道我是否理解他們......),但我的代碼永遠不會很優雅。我想是因爲對Control.Monad
上所有這些功能如何能夠真正幫助的缺乏控制。所以我認爲在使用狀態monad的特定代碼中要求提供這方面的技巧會很好。提示單子更優雅的代碼?
代碼的目的是計算多種隨機遊動的,而它的東西,我想更復雜的東西前做。問題是,我在同時有兩個狀態的計算,我想知道如何優雅撰寫他們:
- ,更新隨機數發生器的功能是類型的東西
Seed -> (DeltaPosition, Seed)
- 該更新隨機遊走的位置功能是
DeltaPosition -> Position -> (Log, Position)
類型(其中Log
只是一些辦法,我報的是隨機遊走的當前位置)的東西。
我所做的是這樣的:
我有一個函數來撰寫這兩狀態計算:
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]
我得到了我想要的東西,這是一種隨機遊走者所佔據的職位列表。但是......我覺得必須有更優雅的方式來做到這一點。我有兩個問題:
我可以重寫這些功能在一個更「一元」的方式,利用
Control.Monad
巧妙的功能呢?是否有關於這樣的結合狀態的一般模式是可以用嗎?這是否與monad變形金剛或類似的東西有關?
順便說一句,這是避免使用'State'數據的構造,因爲在'mtl'的繼任者('單子-fd')是一個好主意,' State'是用'StateT'來定義的,因此'State'數據構造函數不存在。 – 2010-07-31 00:53:05
@TravisBrown實際上,'monads-fd'已被棄用,以'mtl'爲代價。 (意識到你的評論是5歲。) – crockeea 2015-10-27 15:14:14