Изучай Haskell во имя добра! (Липовача) - страница 259

, используйте функцию >state, которая делает то же самое, что делал бы конструктор >State.

Теперь, когда вы увидели, в чём заключается суть вычислений с состоянием и как их можно даже воспринимать в виде значений с контекстами, давайте рассмотрим их экземпляр класса >Monad:

>instance Monad (State s) where

>   return x = State $ \s –> (x, s)

>   (State h) >>= f = State $ \s –> let (a, newState) = h s

>                                       (State g) = f a

>                                   in g newState

Наша цель использования функции >return состоит в том, чтобы взять значение и создать вычисление с состоянием, которое всегда содержит это значение в качестве своего результата. Поэтому мы просто создаём анонимную функцию >\s –> (x, s). Мы всегда представляем значение >x в качестве результата вычисления с состоянием, а состояние остаётся неизменным, так как функция >return должна помещать значение в минимальный контекст. Потому функция >return создаст вычисление с состоянием, которое представляет определённое значение в качестве результата, а состояние сохраняет неизменным.

А что насчёт операции >>>=? Ну что ж, результатом передачи вычисления с состоянием функции с помощью операции >>>= должно быть вычисление с состоянием, верно? Поэтому мы начинаем с обёртки >newtype State, а затем вызываем анонимную функцию. Эта анонимная функция будет нашим новым вычислением с состоянием. Но что же в ней происходит? Нам каким-то образом нужно извлечь значение результата из первого вычисления с состоянием. Поскольку прямо сейчас мы находимся в вычислении с состоянием, то можем передать вычислению с состоянием >h наше текущее состояние >s, что в результате даёт пару из результата и нового состояния: >(a,>newState).



До сих пор каждый раз, когда мы реализовывали операцию >>>=, сразу же после извлечения результата из монадического значения мы применяли к нему функцию >f, чтобы получить новое монадическое значение. В случае с монадой >Writer после того, как это сделано и получено новое монадическое значение, нам по-прежнему нужно позаботиться о контексте, объединив прежнее и новое моноидные значения с помощью функции >mappend. Здесь мы выполняем вызов выражения >f a и получаем новое вычисление с состоянием >g. Теперь, когда у нас есть новое вычисление с состоянием и новое состояние (известное под именем >newState), мы просто применяем это вычисление с состоянием >g к >newState. Результатом является кортеж из окончательного результата и окончательного состояния!

Итак, при использовании операции >>>= мы как бы «склеиваем» друг с другом два вычисления, обладающих состоянием. Второе вычисление скрыто внутри функции, которая принимает результат предыдущего вычисления. Поскольку функции