
Simon Peyton Jones 
259
So that’s all about why laziness is a good thing. It’s also very helpful in a very 
local level in your program. You tend to find Haskell programmers will 
write down a function definition with some local definitions. So they’ll say “f 
of x equals blah, blah, blah where . . .” And in the 
where clause they write 
down a bunch of definitions and of these definitions, not all are needed in all 
cases. But you just write them down anyway. The ones that are needed will 
get evaluated; the ones that aren’t needed won’t. So you don’t have to 
think, “Oh, goodness, all of these sub expressions are going to be evaluated 
but I can’t evaluate that because that would crash because of a divide by 
zero so I have to move the definition into the right branch of the 
conditional.” 
There’s none of that. You tend to just write down auxiliary definitions that 
might be needed and the ones that are needed will be evaluated. So that’s a 
kind of programming convenience thing. It’s a very, very convenient 
mechanism.
But getting back to the big picture, if you have a lazy evaluator, it’s harder to 
predict exactly when an expression is going to be evaluated. So that means 
if you want to print something on the screen, every call-by-value language, 
where the order of evaluation is completely explicit, does that by having an 
impure “function”—I’m putting quotes around it because it now isn’t a 
function at all—with type something like string to unit. You call this function 
and as a side effect it puts something on the screen. That’s what happens in 
Lisp; it also happens in ML. It happens in essentially every call-by-value 
language.
Now in a pure language, if you have a function from string to unit you would 
never need to call it because you know that it just gives the answer unit. 
That’s all a function can do, is give you the answer. And you know what the 
answer is. But of course if it has side effects, it’s very important that you do
call it. In a lazy language the trouble is if you say, “
f applied to print 
"hello"
,” then whether f evaluates its first argument is not apparent to the 
caller of the function. It’s something to do with the innards of the function. 
And if you pass it two arguments, 
f of print "hello" and print "goodbye",
then you might print either or both in either order or neither. So somehow, 
with lazy evaluation, doing input/output by side effect just isn’t feasible. You 
can’t write sensible, reliable, predictable programs that way. So, we had to 
put up with that. It was a bit embarrassing really because you couldn’t really