Монады в JavaScript?

Как выглядит пример кода JavaScript, который использует Monad? Я спрашиваю, потому что понимание Монады намного яснее, если я могу увидеть пример кода (а JavaScript - простой, функциональный язык, который может быть лучшим языком для изучения).

Ответ 1

Я бы начал с написания вашей собственной монады в JavaScript. Монада списка - отличное место для начала; Я нахожу его безусловно полезным. Просто определите функции, которые выполняют следующие действия:

  • Создайте список одного заданного элемента (назовите это mreturn).
  • Создайте пустой список (назовите это mzero).
  • Добавить один список в другой (назовите это mplus).
  • Применить функцию для преобразования каждого элемента в данный список (назовите это map).
  • "Сгладить список списков в простой список, объединив списки (назовите это join).

Это определяет то, что известно как "аддитивная монада" (mzero и mplus образуют "аддитивную" часть). Поиграйте, чтобы увидеть, какие интересные вещи вы можете использовать, используя только эти функции для работы с списками. Например, вы можете вычислить список всех четных чисел в таблице умножения школьника следующим образом:

var nums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var even_products = join(map(join(map(nums, function (x) {
        return map(nums, function(y) { return x * y })
    })),
    function (x) { if (x % 2 == 0) { return mreturn(x) } else { return mzero() } }
));

В качестве альтернативы объедините map и join вместе как одну функцию, определенную как function bind(l, f) { return join(map(l, f)) }. bind может использоваться вместо map и join и используется чаще, например. Haskell. Затем можно записать следующее упражнение:

var nums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var even_products = bind(
    bind(nums, function (x) {
        return bind(nums, function (y) { return mreturn(x * y) })
    }),
    function (x) { if (x % 2 == 0) { return mreturn(x) } else { return mzero() } }
);

Наконец, вы можете захотеть включить эти функции в состав нового прототипа списка (или того, что JavaScript пропускает для классов в наши дни), поэтому вы можете написать jQuery-esque:

var nums = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ];
var even_products = nums
    .bind(function (x) { return nums.bind(function (y) { return mreturn(x * y) }) })
    .bind(function (x) { if (x % 2 == 0) { return mreturn(x) } else { return mzero() } });