Единичная функция JS Monad

Я борюсь с пониманием функции 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

Эти две ссылки специально сделали для меня чудеса. Надеюсь, что это поможет и всем остальным.

Ответ 1

Я не совсем понимаю, что ваш вопрос, но я бы предположил что-то вроде:

Каково правильное определение Монады, и это два метода в терминах JS?

В терминах Хаскелла (взято из https://en.wikibooks.org/wiki/Haskell/Understanding_monads), это просто:

    return :: a -> m a
    (>>=)  :: m a -> (a -> m b) -> m b

    (>>)   :: m a -> m b -> m b

Для терминов JavaScript не смотрите дальше, короткий и простой ответ здесь https://github.com/fantasyland/fantasy-land#monad наряду с другими связанными определениями FP.

Несколько слов о методах:

  • Одна вещь unit (return в Haskell) должна создавать монаду (не точно монаду, но ради аргумента...), поскольку она похожа на конструктор, который помещает значение внутри контейнера, Array.of() - один пример, jQuery() - это еще один и, конечно, new Promise().

    В Спецификации Land of Fantasy это функция/метод of().

  • Вторая важна только потому, что Haskell использует определение монады с unit и bind, в то время как другие (fmap, join) выведены из них.

    Haskell's bind назван chain в Спецификации Земли Фантазии, потому что bind на JavaScript Function.prototype встречается в JavaScript, поэтому кто-то думал, что chain будет достаточно близко.

    И причина, по которой bind i.e. chain "должен" вернуть монаду того же типа из-за (>>=) :: m a -> (a -> m b) -> m b. Короче говоря, функция bind Haskell должна принимать только функцию, которая возвращает монаду (эта часть a -> m b), поэтому вы получаете результат.

  • Haskell's then

    является простым удобством

    и

    последовательности двух монадических действий, когда второе действие не связано с результатом первого, что является общим для монад, таких как IO.

На практике:

  • Это может раздражать вас в JS, поскольку нет строгого принуждения типа, что вы всегда можете не следовать правилам и возвращать все, что хотите, из Promise, например, нарушая цепочку .then() упомянутых обещаний.

  • Некоторые монады, такие как jQuery, имеют "снятые" функции как методы, которые всегда возвращают jQuery, т.е. того же типа, тем самым "защищая" способность к цепочке.