如何基于多镜头定界连续实现协程?

时间:2019-01-12 15:00:54

标签: javascript functional-programming coroutine continuations delimited-continuations

我最近在CPS中使用reset / shift实现了定界连续:

// reset :: ((a -> a) -> a) -> (a -> r) -> r
reset = k => f => f(k(id));

// shift :: ((a -> r) -> (r -> r) -> r) -> (a -> r) -> r
shift = f => k => f(k) (id);

学习理论时,我认识到以下联系:

reset ~ function* // scope of the generator function
shift ~ yield

reset ~ async // scope of the asyn function
shift ~ await

据我了解的理论,JavaScript的生成器是不对称,无堆栈,单发和一流的协程。

  • 不对称意味着被调用的生成器只能屈服于其调用者
  • 无堆栈意味着生成器无法从嵌套函数中产生
  • 单发意味着发电机只能从特定位置恢复一次
  • 第一类意味着可以像正常数据一样传递生成器对象

现在,我想基于reset / shift实现具有以下特征的协程:

  • 不对称
  • 一堆
  • 多次射击
  • 头等舱

查看以下人为设计的示例

const id = x => x;
const mul = x => y => x * y;
const add = x => y => x + y;
const sub = x => y => x - y;

const reset = k => f => f(k(id));
const shift = f => k => f(k) (id);

const of = x => k => k(x);
const lift2 = f => tx => ty => k => tx(x => ty(y => k(f(x) (y))));

const k0 = lift2(sub)
  (reset
    (lift2(add) (of(3))
      (shift
        (k => of(mul(5) (2))))))
          (of(1)); // 9

const k1 = lift2(sub)
  (reset
    (lift2(add) (of(3))
      (shift
        (k => of(k(mul(5) (2)))))))
          (of(1)); // 12

const k2 = lift2(sub)
  (reset
    (lift2(add) (of(3))
      (shift
        (k => of(k(k(mul(5) (2))))))))
          (of(1)); // 15

console.log(k0(id));
console.log(k1(id));
console.log(k2(id));

似乎reset / shift已经满足了最后两个条件,因为定界的延续只是第一类可组合的函数,我可以根据需要多次调用延续k。 要回答原因,我想绕过与列表monad有关的以下limitation。 这些假设正确吗?

即使到目前为止我还没有犯过任何错误,但我对目前任务的复杂性感到不知所措。我不知道如何实现所需的协程,甚至从哪里开始。我也没有找到示例实现。我不希望有一个完整的实施方案,但可能会有一些指导来实现我的目标。

目标

我想绕过Javascript生成器实现的协程的以下限制:

const arrMap = f => xs =>
  xs.map(x => f(x));

const arrAp = fs => xs =>
  fs.reduce((acc, f) =>
    acc.concat(xs.map(x => f(x))), []);

const arrChain = xs => fm =>
  xs.reduce((acc, x) => acc.concat(fm(x)), []);

const arrOf = x => [x];

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

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

const z = function*() {
  const x = yield [1,2,3]
  return [x, x];
}

console.log(
  arrChain([1,2,3]) (x => [x, x]));
 
console.log(
  do_(arrOf, arrChain) (z()));

0 个答案:

没有答案