Я борюсь с пониманием функции unit в JavaScript. В частности, потому что вещь, которая заставила меня "получить" монады (или, по крайней мере, я думал), это объект Promise, и как then
всегда возвращает новое обещание, независимо от того, какую функцию вы передаете на then
, что, насколько мне известно эквивалентно bind
или >>=
в haskell. Это совершенно разумно для меня, потому что это гарантирует, что все ваши функции выполняются в "монадской вселенной", так сказать.
Что меня подводит, это разговор "Монады и Гонады" Дугласа Крокфорда. В своей реализации bind
непосредственно возвращает результат функции преобразования, не проверяя, является ли сам результат, монадой. Это противоречит методу Promises then
, так как then
ALWAYS возвращает новое обещание.
Одна мысль была методом лифта. Его реализация гарантирует, что "лифт" всегда будет возвращать монаду, и, возможно, then
был поднят на обещание. Однако это будет означать, что then !== bind
, и что Promise имеет внутреннее связывание где-то.
Моя интуиция заключается в том, что по крайней мере должна быть какая-то проверка типа в функции привязки, которая проверяет результат преобразования и позволяет разрешить результирующую монаду, но будет перехватывать немоноды и передавать их через единицу опять же, как "лифт".
* EDIT
Кроме того, у меня создается впечатление, что then
эквивалентен bind, flatMap, >>=
, потому что он имеет возможность разворачивать другие монады, в том числе разные и свои собственные. Обращаясь к некоторым ссылкам теории категорий в JavaScript, flatMap
использовался для отображения по набору вложенных массивов, а затем сглаживал их на один размер. Это соответствует тому, как then
будет ждать другого Promises, который вы ему дадите. Но, похоже, это не соответствует первоначальной реализации, упомянутой выше. Я чувствую себя потерянным.
Может ли кто-нибудь, у кого больше опыта в FP, пролить свет на то, что мне не хватает, или я просто отключен, и нужно начинать с самого начала?
Некоторые примеры кода...
// Crockford 'bind'
monad.bind = function(transform) {
// value was passed in through the unit constructor
return transform(value);
}
Моя область проблем
// Set the 'isMonad' prop to be true, for all
// monads made with the MONAD macroid
monad.isMonad = true;
// shouldn't this ALWAYS return a monad?
monad.bind = function(transform) {
var res = transform(value);
return ( res && res.isMonad ) ? res : unit(res);
}
ПРИМЕЧАНИЕ. Я знаю, что я не использую окончательную версию его реализации в полном объеме, я просто фокусируюсь в методе связывания в частности.
Полную реализацию можно найти в
https://github.com/douglascrockford/monad/blob/master/monad.js
Update
После выполнения нескольких исследований >>=
не требуется возвращать экземпляр Monad. Комментарий Берги пролил свет на то, как Promise.prototype.then
перегружен и действует как другая функция в зависимости от того, с чем вы его решаете.
Кроме того, многие вещи начали щелкать, когда я сделал шаг назад и посмотрел, как Монады отличаются от обычных функторов. Детали все еще немного нечеткие, но я думаю, что получаю большую картину.
Несколько хороших ссылок, которые помогли очистить дымку,
Это очень рекомендуется для обзора высокого уровня, в словах человека
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
Не позволяйте фотографиям обманывать вас, этот для меня был как золотой. Не в JavaScript, но все же очень информативно об общих понятиях.
Кроме того, эта серия YouTube по теории категорий в JavaScript
https://www.youtube.com/watch?v=-FkgOHvNAU8&list=PLwuUlC2HlHGe7vmItFmrdBLn6p0AS8ALX&index=1
Эта серия YouTube под названием "Fun Fun Function" замечательна, хост является одним из лучших учителей, которые я нашел в Интернете. Это видео о монадах и было предложено MrE
.
Настоятельно рекомендуется!.
https://www.youtube.com/watch?v=9QveBbn7t_c&app=desktop
Эти две ссылки специально сделали для меня чудеса. Надеюсь, что это поможет и всем остальным.