Типы с кодировкой функций (то есть вложенные функции с карри) имеют некоторые недостатки в Javascript:
- Их представление в консоли разработчика запутано (например,
[Some(5), None]
отображается как [f, f]
) - Ничто не мешает вам применить комбинатор к неправильному типу (например,
eitherMap(f) (Some(5))
) - Вы не можете проверять их свободные переменные
- Вы даже не можете набирать их
Эти недостатки делают их бесполезными в реальных приложениях.
Мне было интересно, есть ли способ преодолеть эти недостатки, и я придумал следующий набросок:
const tag = (name, x, k) => {
const Cons =
Function(`return function ${name}() {}`) ();
Cons.prototype[Symbol.toStringTag] = name;
Cons.prototype["run" + name] = k;
Cons.prototype.tag = name;
const o = new Cons();
Object.defineProperty(o, "value", {get: () => x});
return o;
};
const Some = x =>
tag("Option", x, def =>
tag("Option", x, k => k(x)));
const None = tag("Option", null, def =>
tag("Option", def, k => def));
const option = def => k => fx =>
fx.runOption(def).runOption(k);
const safeInc = option(0) (n => n + 1);
safeInc(Some(5)); // 6
safeInc(None); // 0
const xs = [Some("foo"), None]; // [Option, Option]
/*
expanded dev console display:
1: Option {value: ...} --> expands to "foo"
2: Otpion {value: ...} --> expands to null
*/
Обратите вниманиечто я вообще не заинтересован в наследовании прототипов.
Этот подход утомителен и, вероятно, медленен, потому что я применяю конструктор Function
, что делает код менее предсказуемым.Есть ли лучший способ придать карри функциям тип (или, скорее, тег в JS), чтобы устранить перечисленные недостатки?