Ремонт принтеров, сканнеров, факсов и остальной офисной техники


назад Оглавление вперед




[4]

Монада IO - один из примеров монад без обратной связи в языке Haskell. Так как вы не можете выйти из монады IO, невозможно написать функцию, выполняющую вычисление внутри монады IO и при этом не имеющей в своём результате конструктора типов IO. Это значит, что любая функция, результирующий тип которой не содержит конструктор типов IO, гарантированно не использует монаду IO. Другие монады, такие как List и Maybe, возвращают значения. Поэтому возможно написание функций, которые используют эти монады, но при этом возвращают не монадические значения.

Удивительная черта монад без обратной связи состоит в том, что они могут поддерживать побочные эффекты в своих монадических операциях, предотвращая при этом разрушение функциональных свойств немонадических частей программы.

Рассмотрим простой пример чтения символа, введенного пользователем. Нельзя написать функцию readChar :: Char, потому что она должна каждый раз при вызове возвращать различный символ, в зависимости от того, что ввёл пользователь. Так как Haskell является чистым функциональным языком, то все функции в нём каждый раз при вызове с одними и теми же аргументами должны возвращать одно и то же значение. Зато можно написать функцию ввода/вывода getChar:: IO Char в монаде IO, потому что она может быть использована лишь в последовательности внутри монады без обратной связи. Нет возможности избавиться от конструктора типов IO в сигнатуре какой-либо функции, использующей его, поэтому конструктор типов IO работает как своего рода тег, определяющий функции, которые выполняют операции ввода/вывода. Более того, такие функции полезны лишь внутри монады IO. Таким образом, монада без обратной связи

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

котором правила чистого

монад - это представление при необходимости получения

Другой стандартный приём при определении монадических значений в качестве функций. Тогда значения монадического вычисления «выполняется» результирующая монада и выдаёт результат.

1.4.4. Нулевой элемент и операция «+»

Кроме трёх основных законов, описанных выше, некоторые монады подчиняются дополнительным правилам. У монад есть специальное значение mzero и оператор mplus, который подчиняется четырём дополнительным законам:

1)mzero >>= f == mzero

2)m >>= (\x -> mzero) == mzero

3)mzero mplus m == m

4)m mplus mzero == m

ФП 02005-03 01

Лист 18

№ докум.

Копиоова Формат


Легко запомнить законы для mzero и mplus, если сопоставить mzero с 0, mplus с +, и >> = с * в обычной математике.

Монады, включающие в себя нулевой элемент и операцию «+», можно объявить экземплярами класса MonadPlus в языке Haskell:

class (Monad m) => MonadPlus m where mzero :: m a

mplus :: m a -> m a -> m a

Продолжая использовать монаду Maybe в качестве примера, можно сказать, что она является экземпляром класса MonadPlus:

instance MonadPlus Maybe where mzero = Nothing Nothing "mplus" x = x x "mplus" = x

В данном примере Nothing определяется как нулевое значение, а объединение двух значений Maybe даёт в результате то из этих значений, которое не является Nothing. Если оба входных значения равны Nothing, тогда результатом mplus является также Nothing.

В монаде списка также есть нулевой элемент и операция «+». Нулевым элементом mzero является пустой список, оператором mplus - оператор конкатенации списков ++.

Оператор mplus используется для комбинирования монадических значений из различных вычислений в единственное монадическое значение. В контексте нашего примера клонирования овец можно использовать оператор mplus монады Maybe для определения функции, parent s = (mother s) mplus father s), которая вернёт родителя, если такой есть, или значение Nothing, если у овцы вообще нет родителей. Для овцы с двумя родителями функция mplus вернёт одного из них, в зависимости от точного определения mplus в монаде Maybe.

1.4.5. Резюме

Экземпляры класса Monad должны подчиняться так называемым законам монад, которые описывают алгебраические свойства монад. Три основных закона определяют, что функция return эквивалентна справа и слева, и связывающий оператор ассоциативен. Невыполнение этих требований приведет к тому, что монады будут неправильно функционировать, и может вызвать неявные проблемы при использовании нотации do.

Помимо функций return и >>=, класс Monad определяет другую функцию, fail. Включение функции fail в монаду не является обязательным, но она удобна в использовании и включена в класс Monad, потому что используется нотацией do языка

Haskell.

ФП 02005-03 01

Лист 19

№ докум.

Копипова Формат


Некоторые монады кроме основных трёх законов подчиняются ещё и дополнительным правилам. Одним из важнейших классов таких монад являются монады с нулевым элементом (mzero) и операцией «+» (mplus). Для монад, в которых есть элемент mzero и оператор mplus, используется класс MonadPlus.

1.4.6. Упражнения

Этот раздел содержит несколько простых упражнений для шлифования навыков читателя по созданию монад, а также для укрепления понимания понятия функции и использования монад списка и Maybe перед более глубоким изучением монадического программирования. Упражнения построены на предыдущем примере клонирования овец, с которым читатель уже должен быть знаком.

Упражнение 1: Нотация do

Перепишите функции maternalGrandfather, fathersMaternalGrandmother, и mothersPaternalGrandfather из примера 2, используя монадические операторы return и >>=, без помощи нотации do.

Упражнение 2: комбинирование монадических значений

Напишите функции parent и grandparent с сигнатурой Sheep -> Maybe Sheep. Они должны возвращать одну овцу, отобранную от остальных в соответствии с описанием, или значение Nothing, если такой овцы нет. Подсказка: в данном случае удобно воспользоваться оператором mplus.

Упражнение 3: использование монады списка

Напишите функции parent и grandparent с сигнатурой Sheep -> [Sheep]. Они должны возвращать всех овец, соответствующих описанию, или пустой список, если таких овец нет. Подсказка: в данном случае удобно использовать оператор mplus из монады списка. Также можно воспользоваться функцией maybeToList, определенной в модуле Maybe, для конвертации значения из типа Maybe в список.

Упражнение 4: Использование ограничения класса Monad

Монады обеспечивают модульность и многократное использование кода, инкапсулируя вычислительные алгоритмы в модули, которые могут использоваться для формирования множества различных вычислений. Монады также способствуют модульности, позволяя вам изменять монаду, в которой происходит вычисление, для получения различных вариантов вычислений. Это достигается написанием полиморфных функций в конструкторе типов монады, используя (Monad m) =>, (MonadPlus m) =>, и другие ограничения классов.

ФП 02005-03 01

№ докум.

Копиоова Формат



[стр.Начало] [стр.1] [стр.2] [стр.3] [стр.4] [стр.5] [стр.6] [стр.7] [стр.8] [стр.9] [стр.10] [стр.11] [стр.12] [стр.13] [стр.14] [стр.15] [стр.16] [стр.17] [стр.18] [стр.19] [стр.20] [стр.21] [стр.22] [стр.23] [стр.24] [стр.25]