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

и >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 был различным, мы использовали бы операцию >>>= между двумя разными монадами.

Случайность и монада State

В начале этого раздела мы говорили о том, что генерация случайных чисел может иногда быть неуклюжей. Каждая функция, использующая случайность, принимает генератор и возвращает случайное число вместе с новым генератором, который должен затем быть использован вместо прежнего, если нам нужно сгенерировать ещё одно случайное число. Монада >State намного упрощает эти действия.

Функция >random