What's an example of such a loop?
And the other way round: how do you (sanely) write a state machine as a loop?
See https://en.wikisource.org/wiki/Lambda:_The_Ultimate_GOTO for some examples.
I agree that (most) functions that only ever tail-call themselves can relatively easily be expressed as loops, if for some reason you really love loops. But state machines aren't like that.
With tail calls, you can represent each state as a function, and you can pass different parameters to different states. Very neat, and just works.
But since your example is relying on mutual tail recursion with functions for each state. Yeah, that is much harder to cleanly map to a simple loop. Like obviously making a giant function to cover all the state functions with a giant switch statement is possible, and even relatively common, but not especially clean.
If all state functions have the same parameters, then an approach with functions per state that return the new state and new parameter values, which get called from a loop using a state value to function dictionary can be relatively clean. But if states need different parameters, yeah that gets complicated.
> If all state functions have the same parameters, then an approach with functions per state that return the new state and new parameter values, which get called from a loop using a state value to function dictionary can be relatively clean. But if states need different parameters, yeah that gets complicated.
In a language like Rust, you can encode your state in an enum, and the different variants (= states) in a Rust enum can have different parameters.
Then your implementation basically becomes a loop around a match statement over that enum.
But all you've done here is manually implement a 'trampoline'. The trampoline is to a tail call what manually maintaining a (call) stack is for simulating non-tail calls. See https://en.wikipedia.org/wiki/Trampoline_(computing)#High-le...