One benefit of describing state change as a pure data structure, instead of directly executing it, is that you may now write functions that run these state changes in different ways.
E.g. you may have a dry-run function that doesn't actually change the state but only describes what it would do. Or you could have a function that generates a verbose log of all steps executed. Etc.
That doesn't necessarily work for IO, as that gets special treatment by the runtime, but you can do it with your own types.
Yeah! That's why I'm excited for the effect system to land in OCaml. In general I think effect systems are more user friendly than monads and it makes the choice of how to handle the effects more explicit.
E.g. you may have a dry-run function that doesn't actually change the state but only describes what it would do. Or you could have a function that generates a verbose log of all steps executed. Etc.
That doesn't necessarily work for IO, as that gets special treatment by the runtime, but you can do it with your own types.