и
>put
. Для монады
>State
функция
>get
реализована вот так:
>get = state $ \s –> (s, s)
Она просто берёт текущее состояние и представляет его в качестве результата.
Функция >put
принимает некоторое состояние и создаёт функцию с состоянием, которая заменяет им текущее состояние:
>put newState = state $ \s –> ((), newState)
Поэтому, используя их, мы можем посмотреть, чему равен текущий стек, либо полностью заменить его другим стеком – например, так:
>stackyStack :: State Stack ()
>stackyStack = do
> stackNow <– get
> if stackNow == [1,2,3]
> then put [8,3,1]
> else put [9,2,1]
Также можно использовать функции >get
и >put
, чтобы реализовать функции >pop
и >push
. Вот определение функции >pop
:
>pop :: State Stack Int
>pop = do
> (x:xs) <– get
> put xs
> return x
Мы используем функцию >get
, чтобы получить весь стек, а затем – функцию >put
, чтобы новым состоянием были все элементы за исключением верхнего. После чего прибегаем к функции >return
, чтобы представить значение >x
в качестве результата.
Вот определение функции >push
, реализованной с использованием >get
и >put
:
>push :: Int –> State Stack ()
>push x = do
> xs <– get
> put (x:xs)
Мы просто используем функцию >get
, чтобы получить текущее состояние, и функцию >put
, чтобы установить состояние в такое же, как наш стек с элементом >x
на вершине.
Стоит проверить, каким был бы тип операции >>>=
, если бы она работала только со значениями монады >State
:
>(>>=) :: State s a –> (a –> State s b) –> State s b
Видите, как тип состояния >s
остаётся тем же, но тип результата может изменяться с >a
на >b
? Это означает, что мы можем «склеивать» вместе несколько вычислений с состоянием, результаты которых имеют различные типы, но тип состояния должен оставаться тем же. Почему же так?.. Ну, например, для типа >Maybe
операция >>>=
имеет такой тип:
>(>>=) :: Maybe a –> (a –> Maybe b) –> Maybe b
Логично, что сама монада >Maybe
не изменяется. Не имело бы смысла использовать операцию >>>=
между двумя разными монадами. Для монады >State
монадой на самом деле является >State s
, так что если бы этот тип >s
был различным, мы использовали бы операцию >>>=
между двумя разными монадами.