【问题标题】:How to implement a coroutine for applicative computations?如何为应用计算实现协程?
【发布时间】:2019-06-27 00:27:58
【问题描述】:

这是一个避免嵌套模式的协程,例如 (chain(m) (chain(...)) 用于单子计算:

const some = x => none => some => some(x);
const none = none => some => none;

const option = none => some => tx => tx(none) (some);
const id = x => x;

const of = some;
const chain = fm => m => none => some => m(none) (x => fm(x) (none) (some));

const doM = (chain, of) => gf => {
  const it = gf();

  const loop = ({done, value}) =>
    done
      ? of(value)
      : chain(x => loop(it.next(x))) (value);

  return loop(it.next());
};

const tx = some(4),
  ty = some(5),
  tz = none;

const data = doM(chain, of) (function*() {
  const x = yield tx,
    y = yield ty,
    z = yield tz;

  return x + y + z;
});

console.log(
  option(0) (id) (data)); // 0

但我无法为应用计算实现等效的协程:

const some = x => none => some => some(x);
const none = none => some => none;

const option = none => some => tx => tx(none) (some);
const id = x => x;

const of = some;
const map = f => t => none => some => t(none) (x => some(f(x)));
const ap = tf => t => none => some => tf(none) (f => t(none) (x => some(f(x))));

const doA = (ap, of) => gf => {
  const it = gf();

  const loop = ({done, value}, initial) =>
    done
      ? value
      : ap(of(x => loop(it.next(x)))) (value);

  return loop(it.next());
};

const tx = some(4),
  ty = some(5),
  tz = none;

const data = doA(ap, of) (function*() {
  const x = yield tx,
    y = yield ty,
    z = yield tz;

  return x + y + z;
});

console.log(
  option(0) (id) (data)); // none => some => ...

这应该有效,但它没有。额外的功能包装从何而来?我想我在这里的递归有点迷失了。

顺便说一句,我知道这仅适用于确定性仿函数/单子。

【问题讨论】:

  • 预期的结果是什么? 0?
  • @guest271314 是的。在这个人为的例子中,一元计算和应用计算是可以互换的。
  • js:21 Uncaught TypeError: some is not a function;
  • 为了模仿 Haskell 的 do 表示法,您可能希望生成器的返回值是一元类型,而不是用 of 包装它。
  • doA 中,loop 总是返回一个应用程序,ap 将结果包装在some(f(x)) 中。 ap 的类型是 (M a -> b) -> M a -> M b,但你提升 loop 的方式会导致 (M a -> M b),所以最终结果是 M (M b),而不是预期的 M b

标签: javascript functional-programming monads functor applicative


【解决方案1】:

我无法为应用计算实现等效的协程

是的,因为生成器函数是一元的,而不仅仅是应用程序。 yield 表达式的操作数可以取决于前一个 yield 表达式的结果 - 这是 monad 的特征。

额外的功能包装从何而来?我想我在这里有点迷路了。

你正在做ap(of(…))(…) - 根据Applicative laws,这相当于map(…)(…)。与第一个 sn-p 中的 chain 调用相比,这不会对结果进行任何解包,因此您会得到一个嵌套的 maybe 类型(在您的实现中,它被编码为一个函数)。

【讨论】:

  • 是的,因为生成器函数是单子函数,而不是应用函数。我完全错过了,谢谢!
  • 再想一想你的这部分答案有点误导,因为 monad 是适用的 + 它可能取决于以前的 monadic 计算的值。所以当你说生成器是一元的时,你暗示它们也是适用的。
猜你喜欢
  • 2019-07-16
  • 2022-11-14
  • 1970-01-01
  • 1970-01-01
  • 2011-07-01
  • 1970-01-01
  • 2011-03-27
  • 1970-01-01
  • 2012-10-29
相关资源
最近更新 更多