> An generic future is much harder to be called like this. You need to to create wakers and if you don't properly handle them you'll busy loop. You also need to provide the exact runtime the future needs for its I/O.
You don't actually have to handle I/O with the async runtime if you don't want. You _could_ just poll the futures yourself in a loop, which is roughly the same as what happens if you just call the transition function in a loop for a manual state machine. And likewise if you just keep calling the transition function with empty input you'll also busy-loop.
> And isn't that what blocking code does all the time?
Sure, if you have only one flow you care about or you have threads to take care of your concurrency, this is fine. You can do it with any model (blocking, async, manual state machine).
> - you can easily use it from blocking code without needing a runtime - you can easily use it from async code without blocking the executor
But these things are already true of a state machine compiled from async/await instead of written by hand. `poll()` is just a function, and you can call it where you like. By the contract of `Future`, just like the contract of the state machine transition, it's guaranteed to ‘not block’. The waker machinery exists to help you write engines that decide when to poll, but if you've got your own external notion of that you're free to just call `poll()`. The standard library even has some optimization around this case, e.g. `Waker::noop()`.
> You can for sure describe this as "pure" and "functional", but I bet most people think of a different paradigm when talking about pure functional programming.
I agree, but it's confusing to me that this is the case. Original pure functional programming was all about ‘how can we write more useful programs without any effects’ and ‘what benefits can we get from doing so’. I think those questions are kind of answered; since Moggi's work in the early nineties it's been focused more on ‘how can we keep the benefits of pure functions while also being able to encode effectful logic?’, to which manually-written state machines are a rather primitive sort of answer. They bear pretty strong resemblance to iteratees/transducers/pipes/etc. from that lineage, except that those things aim to build a higher-level combinator language on top to reduce the amount of manual state-machine writing one has to do.