Each step calculates the next state and returns it. You can then compose those state calculators. If you need to save the state that’s IO and you have a bit specifically for it.
It takes a bit of discipline, but generally all state additions should be scoped to the current context. Meaning, when you enter a subcontext, it has become input and treated as holy, and when you leave to the parent context, only the result matters.
But that particular context has become inpure and decried as such in the documentation, so that carefulness is increased when interacting with it.
What about managing state? I think that is an important part and it's easy to mess it.