How to implement a stack-safe chainRec operator for the continuation monad?

前端 未结 2 1848
既然无缘
既然无缘 2020-12-07 03:51

I am currently experimenting with the continuation monad. Cont is actually useful in Javascript, because it abstracts from the callback pattern.

When we

2条回答
  •  情歌与酒
    2020-12-07 04:09

    Did I mess up the implementation of chainRec, or misunderstood the FantasyLand spec, or both or none of it?

    Probably both, or at least the first. Notice that the type should be

    chainRec :: ChainRec m => ((a -> c, b -> c, a) -> m c, a) -> m b
    

    wherein m is Cont and c is your Done/Loop wrapper over a or b:

    chainRec :: ((a -> DL a b, b -> DL a b, a) -> Cont (DL a b), a) -> Cont b
    

    But your chainRec and repeat implementations don't use continations at all!

    If we implement just that type, without the requirement that it should need constant stack space, it would look like

    const chainRec = f => x => k =>
      f(Loop, Done, x)(step =>
        step.done
          ? k(step.value) // of(step.value)(k)
          : chainRec(f)(step.value)(k)
      );
    

    or if we drop even the lazyness requirement (similar to transforming chain from g => f => k => g(x => f(x)(k)) to just g => f => g(f) (i.e. g => f => k => g(x => f(x))(k))), it would look like

    const chainRec = f => x =>
      f(Loop, Done, x)(step =>
        step.done
          ? of(step.value)
          : chainRec(f)(step.value)
      );
    

    or even dropping Done/Loop

    const join = chain(id);
    const chainRec = f => x => join(f(chainRec(f), of, x));
    

    (I hope I'm not going out on a limb too far with that, but it perfectly presents the idea behind ChainRec)

    With the lazy continuation and the non-recursive trampoline, we would however write

    const chainRec = f => x => k => {
      let step = Loop(x);
      do {
        step = f(Loop, Done, step.value)(id);
    //                                  ^^^^ unwrap Cont
      } while (!step.done)
      return k(step.value); // of(step.value)(k)
    };
    

    The loop syntax (initialise step with an f call, do/while instead of do) doesn't really matter, yours is fine as well but the important part is that f(Loop, Done, v) returns a continuation.

    I'll leave the implementation of repeat as an exercise to the reader :D
    (Hint: it might become more useful and also easier to get right if you have the repeated function f already use continuations)

提交回复
热议问题