Читаем Учебник по Haskell полностью

элемент пары с помощью snd, мы выделяем остаток. Функция nextRandom представляет собой генератор

случайных чисел, который принимает значение с предыдущего шага и строит по нему следующее значение.

Построим тип для случайных чисел:

type Random a = State Double a

next :: Random Double

next = State $ \s -> (s, nextRandom s)

Теперь определим функцию, которая прибавляет к данному числу случайное число из интервала от 0 до

1:

addRandom :: Double -> Random Double

addRandom x = fmap (+x) next

Посмотрим как эта функция работает в интерпретаторе:

*Random> runState (addRandom 5) 0.5

(5.5,0.9735000000000014)

*Random> runState (addRandom 5) 0.7

(5.7,0.16289999999999338)

*Random> runState (mapM addRandom [1 .. 5]) 0.5

([1.5,2.9735000000000014,3.139404500000154,4.769488561516319,

5.5250046269694195],0.6226652135290891)

В последней строчке мы с помощью функции mapM прибавили ко всем элементам списка разные случайные

числа, обновление счётчика происходило за кадром, с помощью функции mapM и экземпляра Monad для State.

Также мы можем определить функцию, которая складывает два случайных числа, одно из интервала

[-1+a, 1+a], а другое из интервала [-2+b,2+b]:

addRandom2 :: Double -> Double -> Random Double

addRandom2 a b = liftA2 add next next

where add

a b = \x y -> diap a 1 x + diap b 1 y

diap c r = \x

-> x * 2 * r - r + c

Функция diap перемещает интервал от 0 до 1 в интервал от c-r до c+r. Обратите внимание на то как мы

сначала составили обычную функцию add, которая перемещает значения из интервала от 0 до 1 в нужный

диапазон и складывает. И только в самый последний момент мы применили к этой функции случайные

значения. Посмотрим как работает эта функция:

*Random> runState (addRandom2 0 10) 0.5

(10.947000000000003,0.13940450000015403)

*Random> runState (addRandom2 0 10) 0.7

(9.725799999999987,0.2587662999992979)

Прибавим два списка и получим сумму:

*Random> let res = fmap sum $ zipWithM addRandom2 [1.. 3] [11 .. 13]

*Random> runState res 0.5

(43.060125804029965,0.969511377766409)

*Random> runState res 0.7

(39.86034841613788,0.26599261421101517)

Функция zipWithM является аналогом функции zipWith. Она устроена также как и функция mapM, сначала

применяется обычная функция zipWith, а затем функция sequence.

С помощью типа Random мы можем определить функцию подбрасывания монетки:

Случайные числа | 107

data Coin = Heads | Tails

deriving (Show)

dropCoin :: Random Coin

dropCoin = fmap drop’ next

where drop’ x

| x < 0.5

= Heads

| otherwise = Tails

У монетки две стороны орёл (Heads) и решка (Tails). Поскольку шансы на выпадание той или иной

стороны равны, мы для определения стороны разделяем интервал от 0 до 1 в равных пропорциях.

Подбросим монетку пять раз:

*Random> let res = sequence $ replicate 5 dropCoin

Функция replicate n a составляет список из n повторяющихся элементов a. Посмотрим что у нас полу-

чилось:

*Random> runState res 0.4

([Heads, Heads, Heads, Heads, Tails],0.5184926967068364)

*Random> runState res 0.5

([Tails, Tails, Heads, Tails, Tails],0.6226652135290891)

7.2 Конечные автоматы

С помощью монады State можно описывать конечные автоматы (finite-state machine). Конечный автомат

находится в каком-то начальном состоянии. Он принимает на вход ленту событий. Одно событие происходит

за другим. На каждое событие автомат реагирует переходом из одного состояния в другое.

type FSM s = State s s

fsm :: (ev -> s -> s) -> (ev -> FSM s)

fsm transition = \e -> State $ \s -> (s, transition e s)

Функция fsm принимает функцию переходов состояний transition и возвращает функцию, которая при-

нимает состояние и возвращает конечный автомат. В качестве значения конечный автомат FSM будет возвра-

щать текущее состояние.

С помощью конечных автоматов можно описывать различные устройства. Лентой событий будет ввод

пользователя (нажатие на кнопки, включение/выключение питания).

Приведём простой пример. Рассмотрим колонки, у них есть розетка, кнопка вкл/выкл и регулятор гром-

кости. Возможные состояния:

type Speaker = (SpeakerState, Level)

data SpeakerState = Sleep | Work

deriving (Show)

data Level

= Level Int

deriving (Show)

Тип колонок складывается из двух значений: состояния и уровня громкости. Колонки могут быть вы-

ключенными (Sleep) или работать на определённой громкости (Work). Считаем, что максимальный уровень

громкости составляет 10 единиц, а минимальный ноль единиц. Границы диапазона громкости описываются

такими функциями:

quieter :: Level -> Level

quieter (Level n) = Level $ max 0 (n-1)

louder :: Level -> Level

louder (Level n) = Level $ min 10 (n+1)

Перейти на страницу:

Похожие книги

1С: Бухгалтерия 8 с нуля
1С: Бухгалтерия 8 с нуля

Книга содержит полное описание приемов и методов работы с программой 1С:Бухгалтерия 8. Рассматривается автоматизация всех основных участков бухгалтерии: учет наличных и безналичных денежных средств, основных средств и НМА, прихода и расхода товарно-материальных ценностей, зарплаты, производства. Описано, как вводить исходные данные, заполнять справочники и каталоги, работать с первичными документами, проводить их по учету, формировать разнообразные отчеты, выводить данные на печать, настраивать программу и использовать ее сервисные функции. Каждый урок содержит подробное описание рассматриваемой темы с детальным разбором и иллюстрированием всех этапов.Для широкого круга пользователей.

Алексей Анатольевич Гладкий

Программирование, программы, базы данных / Программное обеспечение / Бухучет и аудит / Финансы и бизнес / Книги по IT / Словари и Энциклопедии
1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных