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


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




[1]

country = Just "China"

Аналогично можно создать тип, применив конструктор типов Maybe к типу:

lookupAge DB -> String -> Maybe Int

Полиморфные типы похожи на контейнеры, которые могут содержать значения многих различных типов. Таким образом, Maybe Int можно считать контейнером типа Maybe, содержащим значение типа Int (или Nothing), а Maybe String - контейнером типа Maybe, содержащим значение типа String (или Nothing). В языке Haskell мы также можем сделать тип контейнера полиморфным, поэтому можно написать «m a» чтобы определить контейнер некоторого типа, содержащий значение некоторого типа!

Мы часто используем переменные с конструкторами типов для описания абстрактных особенностей вычисления. Например, полиморфный тип Maybe a - это тип всех вычислений, результатом которых может быть значение или Nothing. Таким образом, можно говорить о свойствах контейнера, не упоминая о том, что контейнер может содержать.

Получение сообщений, подобных «kind errors», от компилятора во время работы с монадами означает некорректное использование конструкторов типов.

1.2.2. Из чего состоит монада?

В языке Haskell монада определяется конструктором типов (назовем его m), функцией, формирующей значения данного типа (a -> m a), и функцией, комбинирующей это монадическое значение с вычислениями, которые создают значения данного типа для формирования нового значения данного типа (m a -> (a -> m b) -> m b). Заметьте, что контейнер не меняется, в то время как тип содержимого контейнера может изменяться.

Говоря о монадах в целом, принято называть конструктор типов монады m. Функцию, вычисляющую значения данного типа, обычно называют return, а третья функция известна как bind, но записывается как «>>=». Сигнатура функций такова:

-тип монады m data m a = ...

-функция return return :: a -> m a

-bind - функция, связывающая экземпляр монады m a с вычислением, которое создает другой экземпляр монады m b из a для создания нового

-- экземпляра монады m b

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

ФП 02005-03 01


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

Используя аналогию с контейнерами, можно сказать, что конструктор типов m - это контейнер, который может содержать различные значения. Тип m - это контейнер, содержащий значение типа a. Функция return заносит значение в контейнер монады. Функция >>= берёт значение из контейнера монады и передаёт его функции для создания контейнера монады, содержащего новое значение, возможно, другого типа. Функция известна как bind (связывание), потому что она связывает значение в контейнере монады с первым аргументом функции. При добавлении логических операций в связывающую функцию монада может выполнять определённый алгоритм комбинирования вычислений в монаде.

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

1.2.3. Пример

Предположим, что мы пишем программу, прослеживающую проведение экспериментов по клонированию овец. Конечно, нам захочется знать генетическую историю всех наших овец, поэтому нам понадобятся функции mother и father. Но если овцы клонированы, у них не всегда могут быть и отец, и мать!

В нашей реализации на языке Haskell мы опишем возможность отсутствия матери или отца с помощью конструктора типов Maybe:

type Sheep = ...

father Sheep -> Maybe Sheep father = ...

mother :: Sheep -> Maybe Sheep mother = ...

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

maternalGrandfather :: Sheep -> Maybe Sheep maternalGrandfather s = case (mother s) of

Nothing -> Nothing

Just m -> father m

Аналогично для бабушек.

Задача становится ещё сложнее, если мы захотим найти прадедов:

mothersPaternalGrandfather :: Sheep -> Maybe Sheep

ФП 02005-03 01

Лист 10

№ докум.

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


mothersPaternalGrandfather s = case (mother s) of

Nothing -> Nothing Just m -> case (father m) of

Nothing -> Nothing Just gf -> father gf

Такое описание не только уродливо и непонятно, но и слишком громоздко. Очевидно, что значение Nothing в любой точке вычисления приведёт к Nothing в конечном результате, и гораздо удобнее выполнить данное преобразование один раз и удалить из программы подробные описания проверок case. Данные преобразования упростят создание, чтение и изменение кода программы. Для реализации этих преобразований определим следующий комбинатор:

Код содержится в файле example1.hs

- comb - комбинатор для упорядочивания операций, производимых Maybe combMaybe a -> (a -> Maybe b) -> Maybe b

comb Nothing = Nothing

comb (Just x) f = f x

mothersPaternalGrandfather mothersPaternalGrandfather

теперь можно использовать "comb" для формирования сложных последовательностей

:: Sheep -> Maybe Sheep = (Just s) "comb" mother "comb" father "comb" father

Комбинатор отлично работает! Теперь код программы гораздо аккуратнее, с ним легче работать. Заметьте также, что функция comb полностью полиморфна - она никаким образом не специализирована для типа Sheep. Фактически, комбинатор описывает общую стратегию комбинирования вычислений, которые могут не вернуть значение. Таким образом, можно применять данный комбинатор и к другим вычислениям, не всегда возвращающим значение, таким как запросы к базам данных или поиск слов в словарях.

Примечательно, что обычный здравый смысл привёл нас к созданию монады без осознания этого. Конструктор типов Maybe, функция Just (работает как return) и наш комбинатор (работает как >>=) вместе составляют простую монаду для формирования вычислений, которые могут не вернуть значение. Для того, чтобы использовать монаду, остается только согласовать её с встроенным в стандартную библиотеку Haskell набором монад. Этот вопрос является предметом обсуждения в следующей главе.

1.2.4. Список - тоже монада

Как мы уже видели, конструктор типов Maybe - это монада для формирования вычислений, которые могут не вернуть значение. Возможно, вы удивитесь, узнав, что

ИзмПипт

№ докум.

ФП 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]