Монади c вычисления быстро становятся запутанными в JS:
const chain = fm => xs =>
xs.reduce((acc, x) => acc.concat(fm(x)), []);
const of = x => [x];
const main = xs => ys => zs =>
chain(x =>
x === 0
? []
: chain(y =>
chain(z => [[x, y, z]]) (zs)) (ys)) (xs);
console.log("run to completion",
main([1, 2]) (["a", "b"]) ([true, false]));
console.log("short circuiting",
main([0, 2]) (["a", "b"]) ([true, false]));
В Haskell do
запись может использоваться, чтобы скрыть вложенные вызовы функций. Тем не менее, do
- это метод времени компиляции, которого не хватает Javascript.
Функции генератора кажутся подходящими, но они не работают с монадами, которые предоставляют приоритетный выбор. Поэтому я довольно долго искал альтернативу, а недавно придумал аппликатор типа monadi c, чтобы немного распутать вложенные вычисления:
const chain = fm => xs =>
xs.reduce((acc, x) => acc.concat(fm(x)), []);
const of = x => [x];
const id = x => x;
const infixM3 = (w, f, x, g, y, h, z) =>
f(x_ =>
w(x_, w_ => g(y_ =>
w_(y_, w__ => h(z_ =>
w__(z_, id)) (z))) (y))) (x);
const mainApp = xs => ys => zs => infixM3(
(x, k) =>
x === 0
? []
: k((y, k) =>
k((z, k) => [[x, y, z]])),
chain, xs,
chain, ys,
chain, zs);
console.log("run to completion",
mainApp([1, 2]) (["a", "b"]) ([true, false]));
console.log("short circuiting",
mainApp([0, 2]) (["a", "b"]) ([true, false]));
Аппликатор имитирует цепочку в инфиксной позиции, отсюда и название. Он основан на локальных продолжениях, поэтому поднятая функция ожидает пару аргументов, состоящих из связанного значения и продолжения соответственно. Если продолжение не применяется, вычисление замыкается. Это выглядит сложно, но это скорее механический процесс.
Сравнивая явную версию с абстрактной, я думаю, что это улучшение с точки зрения читабельности:
chain(x =>
x === 0
? []
: chain(y =>
chain(z => [[x, y, z]]) (zs)) (ys)) (xs);
infixM3(
(x, k) =>
x === 0
? []
: k((y, k) =>
k((z, k) => [[x, y, z]])),
chain, xs,
chain, ys,
chain, zs);
Продолжения в поднятой функции беспокоит, хотя и тот факт, что аппликатор осведомлен. Кроме того, это совсем не похоже на нотацию. Можем ли мы приблизиться к синтаксису, напоминающему нотацию do
?