如何为应用计算实现协程?
How to implement a coroutine for applicative computations?
这是一个协程,它避免了嵌套模式,例如 (chain(m) (chain(...))
用于 monadic 计算:
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 => ...
这应该行得通,但行不通。额外的功能包装从何而来?我想我在这里的递归有点迷失了。
顺便说一下,我知道这只适用于确定性 functors/monads。
I'm not able to implement an equivalent coroutine for applicative computations
是的,因为生成器函数是一元的,而不仅仅是应用程序。 yield
表达式的操作数可以取决于前一个 yield
表达式的结果——这是 monad 的特征。
Where does the additional functorial wrapping come from? I guess I am a bit lost here.
您正在做 ap(of(…))(…)
- 根据 Applicative laws,这等同于 map(…)(…)
。与第一个片段中的 chain
调用相比,这不会对结果进行任何解包,因此您会得到一个嵌套的 maybe
类型(在您的实现中,它被编码为一个函数)。
这是一个协程,它避免了嵌套模式,例如 (chain(m) (chain(...))
用于 monadic 计算:
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 => ...
这应该行得通,但行不通。额外的功能包装从何而来?我想我在这里的递归有点迷失了。
顺便说一下,我知道这只适用于确定性 functors/monads。
I'm not able to implement an equivalent coroutine for applicative computations
是的,因为生成器函数是一元的,而不仅仅是应用程序。 yield
表达式的操作数可以取决于前一个 yield
表达式的结果——这是 monad 的特征。
Where does the additional functorial wrapping come from? I guess I am a bit lost here.
您正在做 ap(of(…))(…)
- 根据 Applicative laws,这等同于 map(…)(…)
。与第一个片段中的 chain
调用相比,这不会对结果进行任何解包,因此您会得到一个嵌套的 maybe
类型(在您的实现中,它被编码为一个函数)。