reset
我最近在 CPS 中使用/实现了定界延续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 的生成器是非对称的、无堆栈的、一次性的和一流的协程。
- 不对称意味着被调用的生成器只能屈服于它的调用者
- 无堆栈意味着生成器不能从嵌套函数中产生
- one-shot 意味着发电机只能从特定位置恢复一次
- 第一类意味着生成器对象可以像普通数据一样传递
现在我想实现一个基于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
根据需要经常调用延续。为了回答原因,我想绕过与 list monad 相关的以下限制。这些假设是否正确?
即使到目前为止我还没有犯任何错误,我现在也对任务的复杂性感到不知所措。我不知道如何实现所需的协程,甚至不知道从哪里开始。我也没有找到示例实现。我不期望一个完整的实施,但也许一些指导来实现我的目标。
目标
我想绕过 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()));