“Have you tried turning off and on again?” is advice to perform a total state reset, which works because the system’s state is inconsistent but its sources of truth are not.
You never have to reset state if you do not have it in the first place. You get other bugs still, but you don't have the most common class of bugs.
But, you need some state. You just want to discourage it. Some of it can come from laziness, but with difficulty. (Chris Okasaki’s Purely Functional Data Structures uses it to de-amortize the bound on a FIFO queue.) Other things, like ring buffers, are harder to argue.
So you want to be able to express an array of IORefs, say, for your ring buffer. But the people who use it become aware that it is a stateful construct and must be used that way.
Read “what color is your function?” for a counterpoint, of course.
You do it if you're using a language where there's a rule that there are only functions. For example there's no concept of doing one thing followed by another. The only way you can arrange that is to have two functions and compose them: g(f(x)). So now you know that the code in g is executed after the code in f. Monadic composition is basically about doing that while having code that looks like it would in a regular language that has statements and sequential execution. There are a few other reasons, such as you can create your own control flow as-code, lifting, etc. But the primary driver is: because you can't write useful programs in a pure functional language without this trick.
Referential transparency, as the original post says. For example, in a functional language you're always allowed to transform
a = f()
b = f()
c = g(a, b)
into
a = f()
c = g(a, a)
because f() is guaranteed not to have side effects. (If it does return side effects through the IO monad, instead of actually performing the side effects, g receives two data structures that encode what IO operations to perform.) In an imperative/procedural language, f() may have side effects, and if it does the two programs are not equivalent.
This may (not) make programs easier to reason about.
You never have to reset state if you do not have it in the first place. You get other bugs still, but you don't have the most common class of bugs.
But, you need some state. You just want to discourage it. Some of it can come from laziness, but with difficulty. (Chris Okasaki’s Purely Functional Data Structures uses it to de-amortize the bound on a FIFO queue.) Other things, like ring buffers, are harder to argue.
So you want to be able to express an array of IORefs, say, for your ring buffer. But the people who use it become aware that it is a stateful construct and must be used that way.
Read “what color is your function?” for a counterpoint, of course.