Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Получение и установка состоянияСодержание книги
Поиск на нашем сайте
Модуль 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; просмотров: 236; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.216.198 (0.006 с.) |