In Haskell, function computation cannot have side effects within the program. Most of
the side effects in imperative programs are probably the sort of variable reassignment
mentioned in the last panel (whether global variables, or local, or dictionaries, lists, or
other storage structures), but every I/O event is also a sort of side-effect. I/O changes
the world rather than being part of a computation per se. Naturally, there are many
times when what you want to do is change the world in some manner (if not, you
cannot even know a program has run). Haskell circumscribes all such side effects within
a very narrow "box" called Monadic IO. Nothing in a monad can get out, and nothing
outside a monad can get in.
Often, structured imperative programming approaches functional programming’s goals
of circumscribing I/O. Good design might require that input and output only happens in
a limited set of appropriately named functions. Less structured programming tends to
read and write to STDIO, files, graphic devices, etc., all over the place and in a way that
is difficult to predict. Functional programming takes the circumscription to a much
higher level.