Вот какой-то простой код «стартера», расширяющий ваш модуль с некоторыми переформулированиями с точки зрения состояния. Я думаю, вам нужно будет изучить учебник, например, главу LYAH, возиться с ними. Я опускаю подписи, которые становятся все более сложными, но вопрос о типах в ghci будет поучительным. Вам нужно добавить
import Control.Monad.State
import Control.Monad.Writer -- for the position-remembering example
Тогда следующие все должны работать, используя ваше определение move
step = do -- step the state once with your `move`,
sstate <- get -- whatever the state is
put (move sstate)
-- this little program could also be written: `modify move` which shows the
-- link between what you wrote and State a little more clearly
steps = do -- repeatedly apply `step` to the state
Sstate _ _ ls <- get -- til there are no moves, then stop
if null ls
then return() -- could be: unless (null ls) $ do step ; steps
else step >> steps
stepsIO = do -- do all steps as with `steps`, but print
[email protected](Sstate a b ls) <- get -- the current state at each state update
liftIO $ print sstate
if null ls then liftIO (putStrLn "Done!")
else step >> stepsIO
stepsPrintPosition = do -- do all steps as with `steps`, printing
Sstate _ b ls <- get -- only position at each state update
liftIO $ do putStr "current position: "
print b
if null ls then liftIO (putStrLn "Done!")
else do step
stepsPrintPosition
stepsAccumulatePositions = do -- move through all states as with `steps`
[email protected](Sstate a b ls) <- get -- but use `tell` to keep adding the current
tell [b] -- position to the underlying list
if null ls then return() -- of positions
else step >> stepsAccumulatePositions
example = Sstate (Dir 0 1) (Pos 0 2) "ffff"
Чтобы использовать такие вещи, как step
, steps
, stepsIO
и т.д., мы применяем runState
; это дает нам функцию из состояния в новое состояние
runStateT :: StateT s m a -> s -> m (a, s)
Это, конечно, только сбруя для определения ньютайпов
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
Обертка позволяет нам писать фантазии s -> m (a, s)
вещи, используя простой s -> m (a, s)
бит, но под контуром newtype его всегда просто функция s -> m (a, s)
, которую мы пишем в обозначении.
Конечно, раз мы разворачиваем с runStateT
и имеем нашу функцию s -> m (a, s)
, мы должны предоставить его в исходное состояние. Это проще всего увидеть, как это работает путем тестирования в GHCI
>>> example
Sstate (Dir 0 1) (Pos 0 2) "ffff"
>>> runStateT step example -- we step the state once with move
((),Sstate (Dir 0 1) (Pos 0 3) "fff")
>>> runStateT steps example -- we keep stepping till there are no moves
((),Sstate (Dir 0 1) (Pos 0 6) "")
>>> runStateT stepsIO example -- we print state at each state update
Sstate (Dir 0 1) (Pos 0 2) "ffff"
Sstate (Dir 0 1) (Pos 0 3) "fff"
Sstate (Dir 0 1) (Pos 0 4) "ff"
Sstate (Dir 0 1) (Pos 0 5) "f"
Sstate (Dir 0 1) (Pos 0 6) ""
Done!
((),Sstate (Dir 0 1) (Pos 0 6) "")
>>> runStateT stepsPrintPosition example -- print position only at state updates
current position: Pos 0 2
current position: Pos 0 3
current position: Pos 0 4
current position: Pos 0 5
current position: Pos 0 6
Done!
((),Sstate (Dir 0 1) (Pos 0 6) "")
-- the WriterT examples accumulate a 'monoid' of things you keep
-- adding to with `tell xyz` Here we accumulate a [Position]
-- execXYZ and evalXYZ, where they exist, return less information than runXYZ
>>> runWriterT $ runStateT stepsAccumulatePositions example
(((),Sstate (Dir 0 1) (Pos 0 6) ""),[Pos 0 2,Pos 0 3,Pos 0 4,Pos 0 5,Pos 0 6])
>>> execWriterT $ evalStateT stepsAccumulatePositions example
[Pos 0 2,Pos 0 3,Pos 0 4,Pos 0 5,Pos 0 6]
В коде выше я использую mtl
классы типов, а затем с помощью runStateT
и runWriterT
, чтобы «интерпретировать» или специализировать класс с участием подписей. Они относятся к конкретным типам StateT
и WriterT
, определенным в Control.Monad.Trans.{State/Writer}
. Можно опустить классы и просто писать напрямую с помощью конкретных типов, импортируя эти модули. Единственное различие заключается в том, что вам нужно сделать lift $ tell [b]
в одном случае, когда я совмещаю два эффекта, состояние и запись или все, что вы хотите назвать.
Существует много можно сказать об анализе состояния вы работаете, но он появится, как вы могли бы переделать его, если вы думаете, что выше до конца.
читать [этот учебник] (http://learnyouahaskell.com/ для-нескольких-монад-больше) о нескольких монадах, в том числе монадии «Государство». – Bakuriu
То, что я нашел смутным с государственной монадой, состоит в том, что само государство не является на самом деле монадой. что такое xmonad является функция изменения состояния и возвращает значение: s -> (a, s) – mb14
@ mb14 Один из способов понять это, что государство как дополнительный параметр и дополнительное возвращаемое значение; функция типа 'a -> b' становится функцией типа' a -> s -> (b, s) '. Currying позволяет вам думать об этом как о значении типа 'a' и возвращать новую функцию, которая при задании состояния может возвращать значение типа' b' и новое состояние ('a -> (s -> (b, s)). Монада, используя оператор '>> =', является тем, что позволяет объединить эти функции вместе. В конечном итоге вы завершаете функцию типа 's -> (t, s)', которая превращает первоначальное состояние в значение типа 'T' – chepner