【发布时间】:2018-11-06 04:23:25
【问题描述】:
[编辑]
这是How to implement a stack-safe chainRec operator for the continuation monad? 的后续问题
给出的是chainRec的类型
chainRec :: ChainRec m => ((a -> c, b -> c, a) -> m c, a) -> m b
通常,chainRec 与蹦床一起实现,以允许在 monad 中进行堆栈安全递归。但是,如果我们放下蹦床,我们可以为普通函数实现chainRec的类型,如下所示:
const chainRec = f => x => join(f(chainRec(f), of, x));
接下来,我想将它应用到递归动作中:
const map = f => g => x => f(g(x));
const join = f => x => f(x) (x);
const of = x => y => x;
const chainRec = f => x => join(f(chainRec(f), of, x));
const repeat = n => f => x =>
chainRec((loop, done, args) =>
args[0] === 0
? done(args[1])
: loop([args[0] - 1, map(f) (args[1])])) ([n, of(x)]);
const inc = x => of(x + 1);
repeat(10) (inc) (0) (); // error
我想既然chainRec的定义中有一个join,那么repeat的实现中肯定有一个map,所以有两个嵌套的函数上下文可以折叠。然而它不起作用,我不知道如何解决它。
【问题讨论】:
-
您是在询问
chainRec的基本思想还是您的具体问题? -
"通常
chainRec与蹦床一起实现,以允许在 monad 中进行堆栈安全递归。" - 是的,那就是 what thecin the type is all about。 “但是,如果我们放弃蹦床......”那么你根本不应该实现chainRec,而应该简单地实现chain。 -
我想了解的是,如果
chainRec本质上是用map和join实现的chain。由于chain现在包含两个步骤,我们可以将它们分开。映射发生在f(chainRec)和join内chainRec本身内。 -
然后我试图通过一个人为的例子来验证这个模糊的想法,但没有成功。
-
如果没有蹦床,它只会增加意外类型错误的机会,混合 monad 类型和
c类型。我认为这种形式只有助于理解递归是如何工作的。其背后的实际想法最好用chainRec = f => x => unwrapRecAndChain(inLazyRecWrapper(chainRec(f)), stopUnwrap, x))表达。
标签: javascript recursion functional-programming monads