【发布时间】:2021-02-27 03:51:28
【问题描述】:
我有一个数组转换器类型,它展示了交错的效果层,以确保合法的效果实现。您可以从类型的of 操作const arrOfT = of => x => of([of(x)]) 轻松读取结构。
该类型实现了一个有效的折叠作为它的基本操作。我使用左折叠,因为底层数组类型本质上是严格的:
const arrFoldT = chain => f => init => mmx =>
chain(mmx) (mx => {
const go = (acc, i) =>
i === mx.length
? acc
: chain(mx[i]) (x =>
go(f(acc) (x), i + 1))
// ^^^^^^^^^^^^^^^^^^^^^ non-tail call position
return go(init, 0);
});
如您所见,该实现不是堆栈安全的。然而,堆栈安全只是另一个可以通过 monad 编码的计算效果。我为Trampoline 类型实现了一个:
const monadRec = o => {
while (o.tag === "Chain")
o = o.f(o.x);
return o.tag === "Of"
? o.x
: _throw(new TypeError("unknown case"));
};
const recChain = mx => fm =>
mx.tag === "Chain" ? Chain(mx.x) (x => recChain(mx.f(x)) (fm))
: mx.tag === "Of" ? fm(mx.x)
: _throw(new TypeError("unknown case"));
const Chain = x => f =>
({tag: "Chain", f, x});
const Of = x =>
({tag: "Of", x});
虽然实现很简单,但应用程序却并非如此。我很确定我完全错误地应用它:
const mmx = Of(
Array(1e5)
.fill(Chain(1) (x => Of(x))));
// ^^^^^^^^^^^^ redundant continuation
const main = arrFoldT(recChain)
(acc => y => recMap(x => x + y) (acc))
(Of(0))
(mmx);
monadRec(main); // 100000
创建大型有效数组时,我需要使用Chain,因为Of 发出控制流突破蹦床的信号。另一方面,对于Chain,我必须指定一个多余的延续。
我的第一个想法是翻转Chain 的参数并依赖部分应用,但这不适用于当前的实现。
有没有办法更有效地使用类型?
这是一个工作示例:
// ARRAYT
const arrFoldT = chain => f => init => mmx =>
chain(mmx) (mx => {
const go = (acc, i) =>
i === mx.length
? acc
: chain(mx[i]) (x =>
go(f(acc) (x), i + 1))
return go(init, 0);
});
// TRAMPOLINE
const monadRec = o => {
while (o.tag === "Chain")
o = o.f(o.x);
return o.tag === "Of"
? o.x
: _throw(new TypeError("unknown case"));
};
const Chain = x => f =>
({tag: "Chain", f, x});
const Of = x =>
({tag: "Of", x});
// Functor
const recMap = f => tx =>
Of(f(tx.x));
// Monad
const recChain = mx => fm =>
mx.tag === "Chain" ? Chain(mx.x) (x => recChain(mx.f(x)) (fm))
: mx.tag === "Of" ? fm(mx.x)
: _throw(new TypeError("unknown case"));
const recOf = Of;
// MAIN
const mmx = Of(
Array(1e5)
.fill(Chain(1) (x => Of(x))));
const main = arrFoldT(recChain)
(acc => y => recMap(x => x + y) (acc))
(Of(0))
(mmx);
console.log(
monadRec(main)); // 100000
【问题讨论】:
-
Iirc the fantasyland spec has special
ChainRectype 专门为此而设计,您的阵列转换器必须使用它。
标签: javascript functional-programming monads monad-transformers trampolines