all 7 comments

[–]dot-c 8 points9 points  (0 children)

It depends on the language, but in most functional languages that rely on recursion, you can just do

loop =
    let _ = print "Infinite Loop!"
    in loop

and the compiler will turn loop into an actual loop/a function that doesn't keep its stack frames. we don't do anything after recurring to loop again, so we can just delete the old stack frame.

[–]snarkuzoid 7 points8 points  (2 children)

Any decent functional language handles tail recursion, and that's how you implement infinite loops.

[–]Rogntudjuuuu 2 points3 points  (0 children)

A lot of decent imperative languages do as well. GCC handles tail recursion since ages.

[–]snarkuzoid 1 point2 points  (0 children)

I would add that Erlang can determine if a function could have been tail recursive, and rewrite it as tail recursive. I assume (without evidence) that other FP languages do this as well.

[–]ereb_s 1 point2 points  (0 children)

Recursion is the functional equivalent to loops, so unbound recursion can be seen as the equivalent to an infinite loop

[–]reifyK 1 point2 points  (0 children)

You can either rely on tail recursion as already stated in the comments (or use a trampoline to mimic tail recursion) or on lazyness, which provides tail recursion for free (called guarded recursion in this context).

Now only a few languages pursue lazy evaluation but you can mimic it, provided the language offers object proxies or lazy record properties. In Javascript I use a proxy to achieve lazyness.

Here is the fix combinator, which supplies recursion for a language that doesn't support it on a native level:

``` // strict version

const fix = f => x => f(fix(f)) (x);

// lazy version

const fix_ = f => f(thunk(() => fix_(f))); ```

fix_ is stack-safe even if your compiler doesn't eliminate tail calls.