кости. Возможные состояния:
type Speaker =( SpeakerState, Level)
data SpeakerState = Sleep | Work
deriving( Show)
data Level
= Level Int
deriving( Show)
Тип колонок складывается из двух значений: состояния и уровня громкости. Колонки могут быть вы-
ключенными ( Sleep) или работать на определённой громкости ( Work). Считаем, что максимальный уровень
громкости составляет 10 единиц, а минимальный ноль единиц. Границы диапазона громкости описываются
такими функциями:
quieter :: Level -> Level
quieter ( Leveln) = Level $max 0 (n -1)
louder :: Level -> Level
louder ( Leveln) = Level $min 10 (n +1)
Мы будем обновлять значения уровня громкости не напрямую, а с помощью вспомогательных функций
louder и quieter. Так мы не сможем выйти за пределы заданного диапазона.
Возможные события:
108 | Глава 7: Функторы и монады: примеры
data User = Button | Quieter | Louder
deriving( Show)
Пользователь может либо нажать на кнопку вкл/выкл или повернуть реле громкости влево, чтобы при-
глушить звук ( Quieter) или вправо, чтобы сделать погромче ( Louder). Будем считать, что колонки всегда
включены в розетку.
Составим функцию переходов:
speaker :: User -> FSM Speaker
speaker =fsm $trans
wheretrans Button
( Sleep, n) =( Work, n)
trans Button
( Work,
n) =( Sleep, n)
trans Louder
(s,
n) =(s, louder n)
trans Quieter
(s,
n) =(s, quieter n)
Мы считаем, что при выключении колонок реле остаётся некотором положении, так что при следующем
включении они будут работать на той же громкости. Реле можно крутить и в состоянии Sleep. Посмотрим
на типичную сессию работы колонок:
*FSM> letres =mapM speaker [ Button, Louder, Quieter, Quieter, Button]
Сначала мы включаем колонки, затем прибавляем громкость, затем дважды делаем тише и в конце вы-
ключаем. Посмотрим что получилось:
*FSM>runState res ( Sleep, Level2)
([( Sleep, Level2),( Work, Level2),( Work, Level3),( Work, Level2),
( Work, Level1)],( Sleep, Level1))
*FSM>runState res ( Sleep, Level0)
([( Sleep, Level0),( Work, Level0),( Work, Level1),( Work, Level0),
( Work, Level0)],( Sleep, Level0))
Смотрите, изменив начальное значение, мы изменили весь список значений. Обратите внимание на то,
что во втором прогоне мы не ушли в минус по громкости, не смотря на то, что пытались крутить реле за
установленный предел.
Определим колонки другого типа. Наши новые колонки будут безопаснее предыдущих. Представьте си-
туацию, что мы выключили колонки на высоком уровне громкости. Мы слушали домашнюю запись с низким
уровнем звука. Мы выключили и забыли. Потом мы решили послушать другую мелодию, которая записана
с нормальным уровнем звука. При включении колонок нас оглушил шквал звука. Чтобы этого избежать мы
решили воспользоваться другими колонками.
Колонки при выключении будут выставлять уровень громкости на ноль и реле можно будет крутить
только если колонки включены.
safeSpeaker :: User -> FSM Speaker
safeSpeaker =fsm $trans
wheretrans Button
( Sleep, _) =( Work,
Level0)
trans Button
( Work,
_) =( Sleep, Level0)
trans Quieter( Work,
n) =( Work,
quieter n)
trans Louder
( Work,
n) =( Work,
louder n)
trans _
( Sleep, n) =( Sleep, n)
При нажатии на кнопку вкл/выкл уровень громкости выводится в положение 0. Колонки реагируют на
запросы изменения уровня громкости только в состоянии Work. Посмотрим как работают наши новые колон-
ки:
*FSM> letres =mapM safeSpeaker [ Button, Louder, Quieter, Button, Louder]
Мы включаем колонки, делаем по-громче, затем по-тише, затем выключаем и пытаемся изменить гром-
кость после выключения. Посмотрим как они сработают, представим, что мы выключили колонки на уровне
громкости 10:
*FSM>runState res ( Sleep, Level10)
Читать дальше