Наконец-то я понял, как использовать монады (не знаю, понимаю ли я их...), но мой код никогда не бывает очень элегантным. Я предполагаю, что это из-за отсутствия понимания того, как все эти функции на Control.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
?Существует ли общая схема комбинирования подобных состояний, которую можно использовать? Это как-то связано с преобразователями монад или чем-то подобным?
State
, так как в преемникеmtl
(monads-fd
)State
определяется в терминахStateT
, и поэтому конструктор данныхState
не существует. - person Travis Brown   schedule 31.07.2010monads-fd
устарел в пользуmtl
. (Признавая, что вашему комментарию 5 лет.) - person crockeea   schedule 27.10.2015