Монада (программирование)
Из Википедии, бесплатной энциклопедии
Мона́да — особый тип данных в функциональных языках программирования, для которого возможно задать императивную последовательность выполнения некоторых операций над хранимыми значениями[1]. Монады позволяют задавать последовательность выполнения операций, производить операции с побочными эффектами и другие действия, которые сложно или вовсе невозможно реализовать в функциональной парадигме программирования другими способами.
Концепция монады и термин изначально происходят из теории категорий, где она определяется как функтор с дополнительной структурой. Исследования, начатые в конце 1980-х — начале 1990-х годов, установили, что монады могут привнести, казалось бы, разрозненные проблемы компьютерной науки в единую функциональную модель. Теория категорий также выдвигает несколько формальных требований[каких?], так называемых монадических законов, которые должны соблюдаться любой монадой и могут быть использованы для верификации монадического кода.
Описание
[править | править код]Монады чаще всего используются в функциональных языках программирования. При ленивой модели вычисления порядок редукции неизвестен. Например, вычисление 1 + 3 + 6
может быть редуцировано в 1 + 9
или 4 + 6
. Монады позволяют упорядочить редукцию. Поэтому существует ироничное утверждение, что монады — это способ перегрузить оператор «точка с запятой».
Монада является контейнером, который хранит в себе значение произвольного типа. Она должна обладать функцией связывания (bind), которая принимает два аргумента: текущее значение монады и функцию, принимающую значение типа, который содержит текущая монада и возвращающая новую монаду. Результатом вызова функции связывания будет новая монада, полученная путём применения первого аргумента ко второму. Так могла бы выглядеть монада в императивном языке Java и одна из её реализаций, контейнер Maybe:
import java.util.function.Function; interface Monad<T> { <U> Monad<U> bind(Function<T, Monad<U>> f); } class Maybe<T> implements Monad<T> { private final T val; public Maybe(T val) { this.val = val; } public T getVal() { return val; } @Override public <U> Monad<U> bind(Function<T, Monad<U>> f) { if (val == null) return new Maybe<U>(null); return f.apply(val); } } public class MonadApp { public static void main(String[] args) { Maybe<Integer> x = new Maybe<>(5); Monad<Integer> y = x .bind(v -> new Maybe<>(v + 1)) .bind(v -> new Maybe<>(v * 2)); System.out.println( ((Maybe<Integer>)y).getVal() ); } }
Появившиеся в Java 8 функциональные интерфейсы позволяют реализовать интерфейс, похожий на монаду.
В Haskell
[править | править код]Класс Monad присутствует в стандартном модуле Prelude
. Для реализации данного класса требуется любой однопараметрический тип (тип рода * -> *
). Монада обладает четырьмя методами
class Functor f where fmap :: (a -> b) -> f a -> f b class Functor f => Applicative f where pure :: a -> f a (<*>) :: f (a -> b) -> f a -> f b (*>) :: f a -> f b -> f b (<*) :: f a -> f b -> f a -- m :: * -> * class Applicative m => Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b -- реализован по-умолчанию: a >> b = a >>= \_ -> b return :: a -> m a -- = pure fail :: String -> m a -- по-умолчанию вызывает errorWithoutStackTrace
Метод return
может ввести в заблуждение программистов, знакомых с императивными языками: он не прерывает вычисления, а лишь упаковывает произвольное значение типа a
в монаду m
. Метод fail
не имеет отношения к теоретической сущности монад, однако используется в случае ошибки сопоставления с образцом внутри монадического вычисления.[2]). Оператор >>=
является функцией связывания. Оператор >>
— частный случай оператора >>=
, используется когда нам не важен результат связывания.
Некоторые типы, реализующие класс Monad:
IO
, используется для функций с побочным эффектом. Конструкторы IO скрыты от программиста, также отсутствуют функции распаковки монады. Это не позволяет вызывать грязные функции из чистых.Maybe
. Вычисление прерывается, если получено значение Nothing.[] (список)
. Вычисление прерывается при пустом списке. При непустом списке оператор>>=
вызывает функцию для каждого элемента списка.Reader
.Writer
.State
. Помимо возможностей Reader позволяет изменять состояние.
В языке также присутствует do
-нотация, которая является более удобной формой записи монадических функций. В данном примере f1
использует do
-нотацию, а f2
записана с помощью операторов связывания:
f1 = do s <- getLine putStrLn $ "Hello " ++ s putStrLn "Goodbye" f2 = getLine >>= (\s -> putStrLn $ "Hello " ++ s) >> putStrLn "Goodbye"
Примечания
[править | править код]- ↑ Душкин-ФП, 2008, с. 215.
- ↑ Евгений Кирпичев. Монады в Haskell . Архивировано 16 января 2017 года.Монады — «обобщение некоторых привычных идиом, а также как ещё один метод для их абстракции».
Ссылки
[править | править код]Учебные пособия
[править | править код]- Monad Tutorials Timeline (англ.) Большая коллекция пособий по монадам, представлены в порядке появления.
- What the hell are Monads?
- You Could Have Invented Monads! (And Maybe You Already Have.), простое введение
- Monads as Computation
- Monads as Containers
- Monads for the Working Haskell Programmer
- The Haskell Programmer’s Guide to the IO Monad — Don’t Panic
- Introduction to Haskell, Part 3: Monads
- On Monads
- Crash Monad Tutorial (англ.) — статья о монадах, объясняющая их с точки зрения теории категорий
- Learn You a Haskell for Great Good! (англ.) — книга содержит доступное описание языка Haskell, в котором много внимания уделено понятию монады и аналогичным конструкциям
Другие статьи
[править | править код]- A tour of the Haskell Monad functions (англ.)
- Notions of Computation and Monads от Eugenio Moggi, первая статья, предлагающая использование монад в программировании
- «Monads for Functional Programming» от Philip Wadler, описание монад в языке Хаскелл (написано ещё до того, как они в нём появились)
- 4. Монады — простое изложение основ языка
Литература
[править | править код]- Душкин Р.В. Охрана // Приёмы программирования // Функции // Синтаксис и идиомы языка // Справочник по языку Haskell / Гл. ред. Д. А. Мовчан. — М.: ДМК Пресс, 2008. — С. 37—38. — 554 с. — 1500 экз. — ISBN 5-94074-410-9, ББК 32.973.26-018.2, УДК 004.4.
- Душкин Р. В. Функциональное программирование на языке Haskell. — М.: ДМК Пресс, 2008. — 609 с. — ISBN 5-94074-335-8.
- Пейтон-Джонс, Саймон. 8. Лекция: Стандартное начало (Prelude) // Язык и библиотеки Haskell 98.
- Erkok Levent. Value Recursion in Monadic Computations. Oregon Graduate Institute. — 2002. — 162 p.