kongware/scriptum

tail recursion modulo cons doesn't work for higher order calls

ivenmarquardt opened this issue · 1 comments

If the trampoline requires nested Loops.call definitions, i.e. the trampolines call operator receives call operators as arguments, the trampolines winds up in an infinite loop:

L.ap = tf => Loops(tx =>
  tf.run({
    cons: g => tg =>
      tx.run({
        cons: y => ty => Loops.call( // higher order call
          L.Cons(g(y)),
          Loops.call2(tg, L.ap, ty)),
        get nil() {return Loops.done(L.Nil)}
      }),

    nil: L.Nil
  }));

The lazy version works as expected:

L.apLazy = tf => tx =>
  tf.run({
    cons: g => tg =>
      tx.run({
        cons: y => ty => L.Cons(g(y)) (lazy(() => L.apLazy(tg) (ty))),
        nil: L.Nil
      }),

    nil: L.Nil
  });

The actual issue was located inside the Loops trampoline. L.ap requires two arguments but Loops only handle unary functions. Hence a Loops2 variant was necessary, since I want to avoid [] wrapping/unwrapping out of performance considerations.

On a side note L.ap above actually implements the zip list apply instance, not the non-deterministic one.