Interested Article - Монада (программирование)

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

Концепция монады и термин изначально происходят из теории категорий , где она определяется как функтор с дополнительной структурой. Исследования, начатые в конце 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 не имеет отношения к теоретической сущности монад, однако используется в случае ошибки сопоставления с образцом внутри монадического вычисления. ). Оператор >>= является функцией связывания. Оператор >> — частный случай оператора >>= , используется когда нам не важен результат связывания.

Некоторые типы, реализующие класс 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"

Примечания

  1. , с. 215.
  2. Евгений Кирпичев. . 16 января 2017 года. Монады — «обобщение некоторых привычных идиом, а также как ещё один метод для их абстракции».

Ссылки

Учебные пособия

  • (англ.) Большая коллекция пособий по монадам, представлены в порядке появления.
  • , простое введение
  • (англ.) — статья о монадах, объясняющая их с точки зрения теории категорий
  • (англ.) — книга содержит доступное описание языка Haskell, в котором много внимания уделено понятию монады и аналогичным конструкциям

Другие статьи

  • (англ.)
  • от Eugenio Moggi, первая статья, предлагающая использование монад в программировании
  • от , описание монад в языке Хаскелл (написано ещё до того, как они в нём появились)
  • — простое изложение основ языка

Литература

  • Душкин Р.В. Охрана // Приёмы программирования // Функции // Синтаксис и идиомы языка // Справочник по языку 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) // .
  • Erkok Levent. Value Recursion in Monadic Computations. Oregon Graduate Institute. — 2002. — 162 p.
Источник —

Same as Монада (программирование)