Detail: laziness in show

Patrik Jansson patrikj@cs.chalmers.se
Fri, 9 Feb 2001 15:13:21 +0100 (MET)


I just uncountered an interesting example of (hidden) laziness - here is
a very short session with hugs (February 2000):

Prelude> undefined :: String
"
Program error: {undefined}

Note the starting double quote on the line before the error! In a more
complicated context this puzzled me for a while until I realized that
there is an implicit application of show that produces the quote. The show
instance for strings prints a '"' character before it starts evaluating
the argument. (With the setting -u for hugs, nothing is printed.)

So, what about other types? It seems that laziness is not equally
distributed between the show instances:

Prelude> undefined :: Char

Program error: {undefined}

Prelude> undefined :: [Bool]

Program error: {undefined}

... even though one would expect a '\'' character and a '[' character to
be printed.

A closer inspection of the prelude shows that the default definition of
showList is defined by cases (a showChar '[' could be factored out to
mimic the String behaviour) and similarly the definition of showsPrec for
Char could be changed to allow the starting quote to be output
immediately. (showList for Char is an example of how this could be
written)

This is certainly a small detail, but as the variants have different
semantics, and the Prelude is part of the Haskell Report, this is part of
Haskell.

To show that the choice of lazy/strict is not quite obvious we can take
two more types as examples. After a quick look at the definition of show
for pairs,

instance  (Show a, Show b) => Show (a,b)  where
    showsPrec p (x,y) = showChar '(' . shows x . showChar ',' .
                                       shows y . showChar ')'

I thought I could get hugs to print the two characters (" before the
error, but this is the result:

Prelude> undefined :: (String,String)

Program error: {undefined}

A small ~ before the pair (x,y) would change it to what I would have
guessed. Up to this point I thought that maybe all show definitions should
be made as lazy as possible. Finally the last example to show that the
show-for-pair might not be wrong anyway:

instance  Show ()  where
    showsPrec p () = showString "()"

This is also a strict pattern match and the alternative using ~() would
print () both for bottom and for () (that is, for all values of type ()).

So perhaps the odd bird is show for Strings.

/Patrik