[Haskell-cafe] Why?

Robin Green greenrd at greenrd.org
Tue Dec 8 10:00:43 EST 2009

At Thu, 10 Dec 2009 12:07:32 +0000,
Magnus Therning wrote:
> As I understand it it all started with laziness.  I don't know if
> laziness is impossible without purity

More or less.

Haskell is a language where anything can be evaluated lazily by
default. Unlike say Scheme, where if you want something to be
evaluated lazily you have to be explicit about it, in Haskell it's the
opposite - if you want something to be evaluated _strictly_ you have
to be explicit about it.

If you write an impure expression in Haskell (e.g. using
unsafePerformIO) the side-effects of it might be executed once, twice,
or never, depending on the Haskell implementation in use, the
optimisation flags, or even other Haskell code in the system. And the
side-effects might be executed at unpredictable times, in an
unpredictable order, and only some of them might occur. Now,
this might be fine for debugging purposes, where you want to see what
is being done under the hood - but for most other side-effects, you
really want them to occur in a more controllable way.

Hence, to answer John's question, a lazy language _has_ to be pure
(apart from the unsafe functions) because laziness (or, to be more
technically correct, non-strict evaluation) is incompatible with good
control of the side-effects arising from impure code. Both Clean and
Haskell deal with side-effects by allowing the programmer to write
imperative code in a pure way - in Haskell, by using monads or FRP,
and in Clean by using world-passing and uniqueness types.

Now, that answer probably suffices for a Haskell beginner. Of course
eventually you realise time and space usage is a side-effect, and
_that_ needs to be controlled as well... but despite this, I think my
answer is basically right.

However, that's not the _only_ reason why you might want purity. Even in
a strict language, purity makes it easier to reason about code,
because you don't have to consider the environment, only the
parameters that are passed in. Of course, it gets more complicated
with monads, because the Environment monad and the IO monad both give
you implicit environments at the level of "running the monadic
actions". But even then, it's supposed to be easier to reason about
(once you get the hang of it), and I'd broadly agree with this.

More information about the Haskell-Cafe mailing list