Good stuff.

I will have to disagree with (or at least complement) one thing Eric
said: that you have to have lazy evaluation to really avoid side-effects.
I would claim that not even with lazy evaluation, can you avoid
side-effects completely.

The problem is when you include aspects as memory footprint and
timing aspects. These things are very difficult to predict with lazy evaluation, and in many applications, controlling timing and memory
is vital. Partly for this reason, Haskell has strictness annotations to
turn off lazy evaluation.

Not that this is a big problem. You can do lazy evaluation in Erlang
(observe Erlang QuickCheck), but you have to be explicit about it.
Conversely, you must be explicit about strict evaluation in Haskell.
The notion of side-effect free programming is more fundamental,
and states that you must strive to take control of side-effects and
use them only where necessary.

Some side-effects are unavoidable (e.g. the processor gets warm,
as Simon Peyton-Jones pointed out), but may not matter to the
application; other side-effects are unwanted and perhaps
disastrous (some thread frees data which is still needed by
another). In complex systems, control of side-effects is
essential.

/Ulf Wiger