Одне, що робить це заплутаним, - це те, що "популярні" функції, як 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
s join
, це дозволяє нам поєднувати два складених контексти одного типу. Те саме стосується парсерів, може бути і т. Д. І bind
це просто більш практичний спосіб використанняjoin
Отже, монадичний контекст повинен пропонувати лише чотири речі, і він може бути використаний майже з усіма механізмами, розробленими для вводу / виводу, для парсерів, відмов тощо.