Есть ли способ дать карри функциям стрелок тип / тег? - PullRequest
0 голосов
/ 25 ноября 2018

Типы с кодировкой функций (то есть вложенные функции с карри) имеют некоторые недостатки в 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), чтобы устранить перечисленные недостатки?

1 Ответ

0 голосов
/ 25 ноября 2018

Я немного улучшил свой подход и избавился от вызова Function и повторного создания функции конструктора.Это подходит для моего конкретного случая использования (типы с кодировкой функций), но я не смог рассмотреть более общий случай произвольных функций в карри, потому что он все еще слишком утомителен.Во всяком случае, вот оно:

const tag = Cons => (k, ...args) => {
  const o = new Cons();

  Object.defineProperties(o, {
    "value": {get: () => args},
    "runOpt": {value: k}});

  return o;
};


const Opt = tag(
  function Option() {
    Option.prototype[Symbol.toStringTag] = "Option";
    Option.prototype.tag = "Option";
  });


const Some = x =>
  Opt(def => Opt(k => k(x), x), x);

const None = Opt(def => Opt(k => def, def));

const option = def => k => fx =>
  fx.runOpt(def).runOpt(k);

const safeInc = option(0) (n => n + 1);

safeInc(Some(5)); // 6
safeInc(None); // 0

Some(5); // Option {runOption}
[Some("foo"), None]; // [Option, Option]

/*
  expanded dev console display:

  1: Option {runOpt: f, value: ...} --> expands to ["foo"]
  2: Otpion {runOpt: f, value: ...} --> expands to []
*/
...