我终于忍住了如何使用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