Разница между монадой и аппликативным состоит в том, что первый может выбрать следующее вычисление в зависимости от предыдущего результата:
(\x -> if x == 1 then (\_ -> []) else (\y -> (\z -> \w -> [x,y,z]) =<< sqr) =<< (+1)) =<< (+1) $ 0
-- ^
(\w x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) <*> (+1) <*> (+1) <*> sqr $ 0
-- ^^^
Вычисление monadi c может замкнуть вычисление, тогда как с аппликативным мы Я должен использовать всю вычислительную структуру и запускать все эффекты независимо от того, какой ввод мы предоставляем.
Давайте сравним это с liftM
:
liftM3 (\x -> if x == 1 then (\_ _ -> []) else (\y z -> [x,y,z])) (+1) (+1) sqr $ 0
-- ^^^
Это, кажется, скрытый аппликативный стиль. Даже если я заменю оператор лифта на аппликатор monadi c, кажется, что вся структура теряет свое свойство monadi c:
appM3 w f x g y h z =
f(\x' -> g(\y' -> h(\z' -> w x' y' z') z) y) x
appM3 (\x -> if x == 1 then (\_ _ _ -> []) else (\y z _ -> [x, y, z])) (=<<) (+1) (=<<) (+1) (=<<) sqr $ 0
-- ^^^^^
Означает ли это, что правильное вычисление monadi c всегда должно быть кодироваться вручную? Я знаю обозначения, но основной механизм кажется похожим на расширение макроса (пожалуйста, исправьте меня, если это чепуха), так что это не опровергает мое предположение.