Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 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; просмотров: 141; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.138.174.95 (0.012 с.) |