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


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




[2]

другой стандартный конструктор типов в Haskell, [] (для конструирования списков), тоже является монадой. Монада списка позволяет сформировать вычисления, которые дают в результате 0, 1 или более значений.

Функция return для списков просто создаёт список единичной длины (return x = [x]). Операция связывания для списков создаёт новый список, который содержит результаты применения функции ко всем значениям в первоначальном списке (/ >>=f = concatMap f I).

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

Примеры данного использования списковой монады, а также сравнительные примеры использования монады Maybe будут представлены далее. Но сначала рассмотрим, как наиболее используемые монады определены в языке Haskell.

1.2.5. Резюме

Мы выяснили, что монада состоит из конструктора типов, функции, называемой return, и комбинаторной функции, называемой bind или >>=. Эти три элемента инкапсулируют стратегию комбинирования вычислений для составления более сложных вычислений.

С помощью конструктора типов Maybe мы определили простую монаду, которая может использоваться для комбинирования вычислений, не всегда возвращающих значение. Заключив стратегию комбинирования вычислений в монаду, мы добились той степени модульности и гибкости, которая недостижима при обычном объединении вычислений. Также мы увидели, что другой стандартный конструктор типов в Haskell, [], является монадой. Списковая монада инкапсулирует алгоритм комбинирования вычислений, которые могут вернуть 0, 1 или множество значений.

1.3. Работа с классами - классы типов в языке Haskell

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

ФП 02005-03 01

№ докум.

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


1.3.1.Класс Monad

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

Стандартное определение класса Monad в Haskell выглядит примерно так:

class Monad m where

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

return :: a -> m a

1.3.2.Продолжение примера

Возвращаясь к предыдущему примеру, рассмотрим, как конструктор типов Maybe вписывается в систему монад Haskell в качестве экземпляра класса Monad.

Напомню, что наша монада Maybe использует конструктор данных Just в качестве функции return, и мы построили простейший комбинатор, исполняющий роль связывающей функции. Мы можем более явно задать Maybe как монаду, объявив её экземпляром класса Monad:

instance Monad Maybe where

Nothing >>= f = Nothing (Just x) >>= f = f x return = Just

Определив Maybe экземпляром класса Monad, мы можем использовать стандартные операторы для построения сложных вычислений:

-- мы можем использовать монадические операции для построения сложных -- последовательностей

maternalGrandfather :: Sheep -> Maybe Sheep maternalGrandfather s = (return s) >>= mother >>= father

fathersMaternalGrandmother :: Sheep -> Maybe Sheep

fathersMaternalGrandmother s = (return s) >>= father >>= mother >>= mother

Монада Maybe определена как экземпляр класса Monad в модуле Prelude языка Haskell, поэтому вам нет необходимости этим заниматься. Другая монада, с которой мы уже познакомились, конструктор списков, также определена как экземпляр класса Monad в стандартной библиотеке. При написании функций, работающих с монадами,

ФП 02005-03 01

№ докум.

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


постарайтесь использовать класс Monad вместо конкретного экземпляра класса. Функция типа

doSomething (Monad m) => a -> m b

гораздо более гибкая, чем

doSomething :: a -> Maybe b

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

1.3.3. Нотация do

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

Haskell.

Короче говоря, нотация do позволяет проводить монадические вычисления, используя псевдо-императивные конструкции с именованными переменными. Результат монадического вычисления может быть «присвоен» переменной с помощью оператора левой стрелки <-. Затем использование этой переменной в последующем монадическом вычислении автоматически производит связывание. Тип выражения справа от стрелки - монадический тип m a. Выражение справа от стрелки - это образец, сопоставляемый со значением внутри монады. Например, (x:xs) сопоставим Maybe [1, 2, 3].

Вот пример нотации do с использованием монады Maybe:

Код содержится в example2.hs

- мы можем также использовать нотацию do для построения сложных

последовательностей mothersPaternalGrandfather :: Sheep -> Maybe Sheep mothersPaternalGrandfather s = dom <- mother s

gf <- father m father gf

Сравните этот вариант с fathersMaternalGrandmother, определённым выше без использования нотации do. Блок do в данном примере записан определённым образом для определения границ блока. Haskell также позволяет использовать фигурные скобки и точки с запятой при определении блока:

mothersPaternalGrandfather s = do {

m <- mother s; gf <- father m; father gf

ФП 02005-03 01

Лист 14

№ докум.

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



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