Я прочитал много постов, которые объясняют, что такое монады, как unit
и как bind
работают, некоторые из них погружаются прямо в теорию категорий, настолько абстрактную (по крайней мере, для меня), что вызывает кровоточивость глаз, некоторые вообще игнорируют это и касаются странных аналогий буррито, ящики и что нет.
После нескольких недель обучения и большого количества жареных нейронов, (я думаю) я понимаю, как работают монады. Но есть еще одна вещь, которая ускользает от моего понимания, кое-что, о чем действительно касаются несколько постов (кроме IO и состояния):
ПОЧЕМУ?
Почему монады имеют значение? Почему они так важны? Какие проблемы они решают? Можно ли решить эти проблемы только с помощью монад или есть другие способы?
functional-programming
problem-solving
monad
Пустышка я
источник
источник
Ответы:
Вам не нужны монады, чтобы что-то решить. Они просто делают некоторые вещи проще. Многие люди слишком абстрактны и теоретичны при объяснении монад. В основном, монады - это паттерн, который снова и снова появляется в программировании. Распознав этот шаблон, мы можем упростить наш код и избежать переопределения некоторых функций.
Для Хаскелла, с конкретной точки зрения, наиболее заметная вещь, которую позволяют монады, это делать нотацию . Постижения списков в Haskell и других языках также используют в своих интересах монады. Вы также можете создавать библиотеки, такие как Control.Monad .
Все это обеспечивает полезные упрощения, и как только вы внедрили его для одной монады, вы автоматически получите его для всех монад. Это одна из основных причин, почему повторное использование кода намного проще для функционального программирования, чем другие парадигмы.
источник
IO
это самая выдающаяся монада Хаскелла , но я не приводил примеров отдельных монад. Я перечислял примеры всеобъемлющих абстракций, которые они позволяют. Я пытался понять, почему, например, первый парень, который подумает об использовании монады для IO, подумает, что это хорошая идея в целом.Это легче понять, если вы посмотрите на конкретные монады и посмотрите, какие проблемы они решают. Например, в Haskell:
IO: Позволяет представлять IO в системе типов, поэтому вы можете очистить отдельные чистые функции от функций, выполняющих IO.
Список: Позволяет вам делать списки и нодерминистские вычисления.
Возможно: Лучшая альтернатива нулям и поддержка чего-то сравнимого с оператором ноль-слияния C #.
Parsec: удобный DSL для написания парсеров.
Поэтому легко (я надеюсь) увидеть обоснование для отдельных монад, так как они все довольно полезны. Но проблемы, которые они решают, также весьма различны, и на первый взгляд они, похоже, не имеют много общего, за исключением того, что все они связаны с некоторой логикой для операций цепочки. Монады полезны, потому что они позволяют создавать такие разнообразные инструменты.
Могут ли приведенные выше примеры быть реализованы без монад? Конечно, они могут быть реализованы специальным образом, но наличие монад, встроенных в язык, обеспечивает прямую поддержку языка, например
do
-notation, которая работает со всеми монадами.источник
Одна вещь, которая делает это запутанным, - то, что "популярные" функции как
bind
и<*>
ориентированы на практику. Но чтобы понять концепции, проще сначала взглянуть на другие функции. Также стоит отметить, что монады выделяются, потому что они немного преувеличены по сравнению с другими связанными понятиями. Поэтому я начну с функторов.Функторы предлагают функцию (в нотации Haskell)
fmap :: (Functor f) => (a -> b) -> f a -> f b
. Другими словами, у вас есть контекст, вf
который вы можете поднять функцию. Как вы можете себе представить, почти все является функтором. Списки, Возможно, Либо, функции, ввод / вывод, кортежи, парсеры ... Каждый представляет контекст, в котором может появляться значение. Таким образом, вы можете написать чрезвычайно универсальные функции, которые работают практически в любом контексте, используяfmap
или его встроенный вариант<$>
.Что еще вы хотите сделать с контекстами? Возможно, вы захотите объединить два контекста. Таким образом , вы можете получить обобщение
zip :: [a] -> [b] -> [(a,b)]
, например , как это:pair :: (Monoidal f) => f a -> f b -> f (a,b)
.Но потому , что это еще более полезным на практике, Haskell библиотеки вместо этого предлагают
Applicative
, который представляет собой комбинациюFunctor
иMonoidal
, а такжеUnit
, что только добавляет , что вы можете поместить значения «внутри» свой контекст сunit
.Вы можете написать чрезвычайно общие функции, просто указав эти три вещи в контексте, в котором вы работаете.
Monad
это просто еще одна вещь, которую вы можете заявить в дополнение к этому. Раньше я не упоминал о том, что у вас уже есть два способа объединить два контекста: вы можете не только создаватьpair
их, но и составлять их, например, иметь список списков. В контексте ввода-вывода примером может служить действие ввода-вывода, которое может читать другие действия ввода-вывода из файла, поэтому у вас будет типFilePath -> IO (IO a)
. Как мы можем избавиться от этого стека, чтобы получить исполняемую функциюIO a
? Вот где приходитMonad
sjoin
, это позволяет нам комбинировать два сложенных контекста одного типа. То же самое касается парсеров, может быть и т. Д. Иbind
это просто более практичный способ использованияjoin
Таким образом, монадический контекст должен предлагать только четыре вещи, и его можно использовать практически со всеми механизмами, разработанными для ввода-вывода, для синтаксических анализаторов, для сбоев и т. Д.
источник
Monads позволяет вам выражать различные не чистые вычисления, а также упрощать код
И, что важно, без компромисса с чисто языковыми конструкциями и извлечения из него более чистого языка
источник
Maybe
не связанных с чем-то внешним.