Наконец-то я понял, как использовать монады (не знаю, понимаю ли я их ...), но мой код никогда не бывает очень изящным. Я думаю, из-за отсутствия хватки, как все эти функции на 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' (в 'монады-fd'),' State' определяется в терминах 'StateT', и поэтому конструктор данных' State' не существует. –
@TravisBrown На самом деле, 'monads-fd' устарел в пользу' mtl'. (Признавая, что вашему комментарию 5 лет.) – crockeea