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


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




[3]

Заметьте, что нотация do имеет сходство с императивным языком программирования, в котором вычисление формируется из определённой последовательности простейших вычислений. В этом отношении монады предлагают возможность создания императивных вычислений в составе функциональной программы. Эта тема будет рассмотрена подробнее при обсуждении побочных эффектов и монады IO позднее.

Нотация do - всего лишь синтаксический приём. Нет ничего, что можно сделать с помощью нотации do, и нельзя сделать с помощью стандартных монадических операторов. Но нотация do более удобна в некоторых случаях, особенно при длинной последовательности монадических вычислений. Необходимо понимать и стандартную монадическую связывающую запись, и нотацию do, и уметь применять их в соответствующем случае. Фактически, при приведении нотации do к стандартным монадическим операторам каждое выражение, сопоставленное с образцом, x <- expr1, становится

exprl >>= \x ->

и каждое выражение без означивания, expr2, становится

expr2 >>= \ ->

Все блоки do должны заканчиваться монадическим выражением, клоз let допускается в начале блока do (но клозы let в блоках do не используют ключевое слово in). Определение, описанное выше, может быть преобразовано в следующий код:

mothersPaternalGrandfather s = mother s >>= \m ->

father m >>= \gf ->

father gf

Теперь становится понятным, почему связывающий оператор так называется. Он используется буквально для связывания значения внутри монады с аргументом последующего -выражения.

1.3.4. Резюме

Язык Haskell располагает встроенными средствами поддержки монад. Для использования этих средств вам необходимо объявить конструктор типов вашей монады экземпляром класса Monad и предоставить описания функций return и >>= (называемой «связыванием») вашей монады. Монада, являющаяся экземпляром класса Monad, может быть использована с нотацией do, которая является синтаксическим приёмом, обеспечивающим простую императивную запись для описания вычислений с монадами.

ФП 02005-03 01

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


1.4. Законы монад

До этого момента учебное пособие избегало технических подробностей, но есть несколько технических моментов, касающихся монад, которые требуют разъяснения. Монадические операции должны придерживаться законов, известных как «аксиомы монад». Соблюдение данных законов не проверяется компилятором языка Haskell, поэтому обеспечение этого является задачей программиста. Класс Monad в Haskell включает также несколько функций, выходящих за пределы минимального определения, с которыми мы ещё не знакомы. Наконец, многие монады подчиняются дополнительным законам, не входящим в состав стандартных законов монад, и существует дополнительный класс в Haskell для поддержки этих монад.

1.4.1.Три основных закона

Концепция монады берёт начало в направлении математики, называемом теорией категорий. Хотя нет необходимости в знании теории категорий для создания и использования монад, нам необходимо придерживаться некоторых математических формализмов. Для создания монады недостаточно задать экземпляр класса Monad с корректными характеристиками типов. Для того чтобы монада была составлена правильно, необходимо, чтобы функции return и >>= работали вместе согласно трём правилам:

1)(return x) >>= f == f x

2)m >>= return == m

3)(m >>= f) >>= g == m >>= (\x -> f x >>= g)

Первое правило требует, чтобы функция return была эквивалентна слева по отношению к >>=. Второе правило требует, чтобы функция return была эквивалентна справа по отношению к >>=. Третье правило представляет собой закон ассоциативности для >>=. Соблюдение этих законов обеспечит непротиворечивость семантики нотации do, использующей монаду.

Любой конструктор типов с операторами return и bind, удовлетворяющими трём законам монад, это монада. Компилятор языка Haskell не проверяет соблюдение данных законов для каждого экземпляра класса Monad. Обеспечение соответствия создаваемых монад данным законам - задача программиста.

1.4.2.В случае ошибки

Ранее было приведено лишь минимальное определение класса Monad. Полное определение данного класса на самом деле включает ещё две дополнительные функции:

faiI и >> .

ФП 02005-03 01

№ докум.


£ то

Реализация функции fail по умолчанию выглядит так:

fail s = error s

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

fail = Nothing

Таким образом, функция fail возвращает экземпляр монады Maybe с определённой характеристикой, когда она связывается с другими функциями монады Maybe.

Функция fail не является обязательной частью математического определения монады, но она включена в стандартное определение класса Monad из-за роли, которую она исполняет нотации do языка Haskell. Функция fail вызывается каждый раз при неудаче сопоставления с образцом в блоке do:

fn:: Int -> Maybe [Int]

fn idx = do

let l = [Just [1, 2, 3], Nothing, Just [], Just [7..20]] (x:xs) <- l !! idx -- ошибка при сопоставлении с образцом

-- вызовет функцию fail

return xs

В данном примере fn 0 имеет значение Just [2, 3], но fn 1 и fn 2 имеют значение Nothing.

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

(>>) :: m a -> m b -> m b

m >> k = m >>= (\ -> k)

1.4.3. Монады, не возвращающие значение

Вы могли заметить, что из монады, являющейся экземпляром стандартного класса Monad, нельзя извлечь значение. Это не проблема. Ничто не мешает автору монады использовать специальные функции. Например, значения могут быть извлечены из монады с помощью сравнения с образцом Just x или использования функции fromJust.

Не требуя подобных функций, класс Monad языка Haskell позволяет создавать монады без обратной связи. В такую монаду значение можно передать через функцию return (а иногда и через функцию fail), а также можно выполнить вычисления внутри монады, используя функции связывания >>= и >>. Однако из такой монады нет возможности извлечь значения.

ФП 02005-03 01

Лист 17

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



[стр.Начало] [стр.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]