Одна вещь, которая делает это запутанным, - то, что "популярные" функции как 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? Вот где приходит Monads join, это позволяет нам комбинировать два сложенных контекста одного типа. То же самое касается парсеров, может быть и т. Д. И bindэто просто более практичный способ использованияjoin
Таким образом, монадический контекст должен предлагать только четыре вещи, и его можно использовать практически со всеми механизмами, разработанными для ввода-вывода, для синтаксических анализаторов, для сбоев и т. Д.