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.