How to Replace While Loops with a Functional Programming Alternative Without Tail Call Optimization

How do I replace while loops with a functional programming alternative without tail call optimization?

An example in JavaScript

Here's an example using JavaScript. Currently, most browsers do not support tail call optimisation and therefore the following snippet will fail

const repeat = n => f => x =>  n === 0 ? x : repeat (n - 1) (f) (f(x))  console.log(repeat(1e3) (x => x + 1) (0)) // 1000console.log(repeat(1e5) (x => x + 1) (0)) // Error: Uncaught RangeError: Maximum call stack size exceeded

While or Tail Recursion in F#, what to use when?

The best answer is 'neither'. :)

There's some ugliness associated with both while loops and tail recursion.

While loops require mutability and effects, and though I have nothing against using these in moderation, especially when encapsulated in the context of a local function, you do sometimes feel like you're cluttering/uglifying your program when you start introducing effects merely to loop.

Tail recursion often has the disadvantage of requiring an extra accumulator parameter or continuation-passing style. This clutters the program with extra boilerplate to massage the startup conditions of the function.

The best answer is to use neither while loops nor recursion. Higher-order functions and lambdas are your saviors here, especially maps and folds. Why fool around with messy control structures for looping when you can encapsulate those in reusable libraries and then just state the essence of your computation simply and declaratively?

If you get in the habit of often calling map/fold rather than using loops/recursion, as well as providing a fold function along with any new tree-structured data type you introduce, you'll go far. :)

For those interested in learning more about folds in F#, why not check out my first three blog posts in a series on the topic?

How to implement an infinite update loop in a functional way

If there was a tail recursion optimization, the generated code would be very similar to something like

void RunUpdateLoop(WorldState world) {
while(1) { world = RunUpdateLoop(world); }
}

No?

Of course you could say that's not "functional" enough, but you're asking for a "functional" solution in a procedural language. So, not quite sure what you are after.

You can always simulate a call stack in the heap with a stack-like data structure, and do the tail-recursion optimization yourself, but in this case it will once again collapse to something very similar to the above.

While or Tail Recursion in F#, what to use when?

The best answer is 'neither'. :)

There's some ugliness associated with both while loops and tail recursion.

While loops require mutability and effects, and though I have nothing against using these in moderation, especially when encapsulated in the context of a local function, you do sometimes feel like you're cluttering/uglifying your program when you start introducing effects merely to loop.

Tail recursion often has the disadvantage of requiring an extra accumulator parameter or continuation-passing style. This clutters the program with extra boilerplate to massage the startup conditions of the function.

The best answer is to use neither while loops nor recursion. Higher-order functions and lambdas are your saviors here, especially maps and folds. Why fool around with messy control structures for looping when you can encapsulate those in reusable libraries and then just state the essence of your computation simply and declaratively?

If you get in the habit of often calling map/fold rather than using loops/recursion, as well as providing a fold function along with any new tree-structured data type you introduce, you'll go far. :)

For those interested in learning more about folds in F#, why not check out my first three blog posts in a series on the topic?

Can fix be tail recursive and thus expressed as a simple loop?

I can't figure out how to express fix as a tail recursive algorithm.

First, convert the definition of fix into A-normal form.

// fix :: ((a -> b) -> a -> b) -> a -> b
const fix = f => x => {
const g = fix(f);
const h = f(g);
const y = h(x);
return y;
};

Next, convert the resulting program into continuation-passing style.

// type Cont r a = (a -> r) -> r

// fix :: ((a -> Cont r b) -> Cont r (a -> Cont r b)) -> Cont r (a -> Cont r b)
const fix = f => k => k(x => k =>
fix(f) (g =>
f(g) (h =>
h(x) (y =>
k(y)))));

Now, fix is tail recursive. However, this is probably not what you want.

A tail recursive algorithm could be easily transformed to a stack safe loop. That is the actual goal.

If all you want is stack safety, then you could use the Trampoline monad.

// Bounce :: (a -> Trampoline b) -> a -> Trampoline bconst Bounce = func => (...args) => ({ bounce: true, func, args });
// Return :: a -> Trampoline aconst Return = value => ({ bounce: false, value });
// trampoline :: Trampoline a -> aconst trampoline = result => { while (result.bounce) result = result.func(...result.args); return result.value;};
// fix :: ((a -> Trampoline b) -> a -> Trampoline b) -> a -> Trampoline bconst fix = f => Bounce(x => f(fix(f))(x));
// id :: a -> aconst id = x => x;
// reachable codeconsole.log("begin"); // open the console in your browser
// infinite looptrampoline(fix(id)(0));
// unreachable codeconsole.log("end");

Is there a way to call a function without adding to the call stack?

My solution is to write an exec() routine that stops the recursion:

template<typename Func>
void exec(const Func& f)
{
using function_t = Func;
static std::map<const function_t*, size_t> functions;
const auto it = functions.find(&f);
if (it == functions.end())
{
functions[&f] = 1;
while (functions[&f] > 0)
{
f();
functions[&f]--;
}
functions.erase(&f);
}
else
{
functions[&f]++;
}
}

With that utility, I can more-or-less preserve the appearance of the existing code

class test4 final
{
int i = 0;
void goto_loop_() {
i++;
if (i > 10) goto_done(); }
void goto_loop() { goto_loop_(); static const auto f = [&]() { goto_loop(); }; exec(f); }
void goto_done()
{
exit(EXIT_SUCCESS);
}
public:
test4() { goto_loop(); }
};

(Using a lambda avoids hassles with pointers to members functions.)

how to call a function and use a global variable in that function

I'm not sure how to use n in loop function.

You can't, that what makes nested function definitions so popular :-) You would need to add a fourth parameter, and pass that through all of your recursive calls unaltered:

let rec loop i n a b = 
if i = n then a
else loop (i+1) (n) (b) (a+b)

let fib n =
loop 0 n 0 1

Alternatively, you change the looping structure so that it doesn't count i up from 0 to n, but rather have a variable (say j) count down from n so you only need to check when it reaches 0 in loop:

let rec loop j a b = 
if j = 0 then a
else loop (j-1) (b) (a+b)

let fib n =
loop n 0 1


Related Topics



Leave a reply



Submit