Получение и установка состояния

We use cookies. Read the Privacy and Cookie Policy

Модуль Control.Monad.State определяет класс типов под названием MonadState, в котором присутствуют две весьма полезные функции: get и 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 был различным, мы использовали бы операцию >>= между двумя разными монадами.