Skip to content

Show

When we evaluate a numeric expression in GHCi, GHCi displays the result:

GHCi
>>> 1 + 2
3

Or even more obviously, when we enter a number, GHCi prints the number we entered, because the value of this trivial expression is simply the number itself:

GHCi
>>> 517
517

Now let's try this with banner numbers:

GHCi
>>> newtype BannerNumber = B Int
>>> B 1

<interactive>:25:1: error:
    • No instance for (Show BannerNumber) arising from a use of ‘print’
    • In a stmt of an interactive GHCi command: print it

Huh, that didn't work so well. Clearly, to display some value on screen, GHCi needs to know how to convert it into a string that it can print. As I said before, any type we define does not support any operations out of the box. This includes conversion to a string to print it.

Show is the class of all types that can be "shown", of all types for which we have implemented a conversion to String:

GHCi
>>> :info Show
type Show :: * -> Constraint
class Show a where
  showsPrec :: Int -> a -> ShowS
  show :: a -> String
  showList :: [a] -> ShowS
  {-# MINIMAL showsPrec | show #-}
    -- Defined in ‘GHC.Show’
[More omitted output]

Most of the time, the only function you care about is show. It can be used to convert a value of type a to a corresponding string representation, of type String obviously. showsPrec can be used to correctly format expressions so they can be read back using readsPrec, which is part of the Read class discussed next. The "Prec" part stands for "precedence". We won't discuss showsPrec in detail. showList is a bit of a hack. Recall that a list of integers is printed between square brackets: [1,4,2]. A list of characters, on the other hand, is printed as a string:

GHCi
>>> ['a'..'z']
"abcdefghijklmnopqrstuvwxyz"

This is enabled by showList. showList is used to display lists. The default implementation displays the list elements between square brackets and separated by commas. The showList implementation for the Char type overrides the default implementation and instead prints the characters in the list between double quotes.

Note, however, that the return type of showList isn't String. It's ShowS. showsPrec has the same return type. This type is defined as

type ShowS = String -> String

It's a function from String to String. The reason why showsPrec and showList have this type is a bit technical. When we convert a complex structure into a string representation, we need to build up this string representation from the string representations of the parts of our structure. Now, since strings are lists of characters, this involves a whole lot of list concatenations, and list concatenation is slow: it takes linear time in the length of its first argument. Thus, the low level functions to convert values to strings use an accumulator a bit like a StringBuilder in Java. When building up a string representation of a complex structure, we start with the empty string. We call showsPrec on the components of the structure, and each component add its representation to this string, at the front, not at the back, because prepending to a list is fast.