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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



 
 

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

 

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

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

 
 

Функция random из модуля System.Random имеет следующий тип:

random:: (RandomGen g, Random a) => g –> (a, g)

Это значит, что она берёт генератор случайных чисел и произ- водит случайное число вместе с новым генератором. Нам видно, что это вычисление с состоянием, поэтому мы можем обернуть его в конструктор newtype State при помощи функции state, а затем


 

 
 

использовать его в качестве монадического значения, чтобы пере- дача состояния обрабатывалась за нас:

import System.Random import Control.Monad.State

 

 
 

randomSt:: (RandomGen g, Random a) => State g a randomSt = state random

Поэтому теперь, если мы хотим подбросить три монеты (True – это «решка», а False – «орёл»), то просто делаем следующее:

import System.Random import Control.Monad.State

 

threeCoins:: State StdGen (Bool, Bool, Bool) threeCoins = do

a <– randomSt b <– randomSt c <– randomSt

 
 

return (a, b, c)

Функция threeCoins – это теперь вычисление с состоянием, и после получения исходного генератора случайных чисел она пе- редаёт этот генератор в первый вызов функции randomSt, которая производит число и новый генератор, передаваемый следующей функции, и т. д. Мы используем выражение return (a, b, c), чтобы представить значение (a, b, c) как результат, не изменяя самый пос- ледний генератор. Давайте попробуем:

 
 

ghci> runState threeCoins (mkStdGen 33) ((True,False,True),680029187 2103410263)

Теперь выполнение всего, что требует сохранения некоторого состояния в промежутках между шагами, в самом деле стало достав- лять значительно меньше хлопот!

 



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 138; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.117.153.38 (0.009 с.)