tail recursion modulo cons doesn't work for higher order calls
ivenmarquardt opened this issue · 1 comments
ivenmarquardt commented
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
});
ivenmarquardt commented
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.