While we’ve talked a little about types already, our interactions with ghci have so far been free of much type-related thinking. We haven’t told ghci what types we’ve been using, and it’s mostly been willing to accept our input.
Haskell requires type names to start with an uppercase letter, and variable names must start with a lowercase letter. Bear this in mind as you read on; it makes it much easier to follow the names.
The first thing we can do to start exploring the world of types is to get ghci to tell us more about what it’s doing. ghci has a command, :set, that lets us change a few of its default behaviors. We can tell it to print more type information as follows:
ghci>
:set +t
ghci>
'c'
'c' it :: Charghci>
"foo"
"foo" it :: [Char]
What the +t
does is tell
ghci to print the type of an
expression after the expression. That cryptic it
in the output can be very
useful: it’s actually the name of a special variable, in which ghci stores the result of the last expression
we evaluated. (This isn’t a Haskell language feature; it’s specific to
ghci alone.) Let’s break down the
meaning of the last line of ghci
output:
Here are a few more of Haskell’s names for types, from expressions of the sort that we’ve already seen:
ghci>
7 ^ 80
40536215597144386832065866109016673800875222251012083746192454448001 it :: Integer
Haskell’s integer type is named Integer. The size of an Integer value is bounded only by your system’s memory capacity.
Rational numbers don’t look quite the same as integers.
To construct a rational number, we use the (%)
operator. The numerator is on the left, the denominator on the
right:
ghci>
:m +Data.Ratio
ghci>
11 % 29
11%29 it :: Ratio Integer
For convenience, ghci lets us abbreviate many commands, so we can write :m instead of :module to load a module.
Notice there are two words on the
righthand side of the ::
in the preceding code. We can read
this as a “Ratio of Integer.” We might guess that a Ratio
must have values of type Integer as both numerator and
denominator. Sure enough, if we try to construct a Ratio
where the numerator and denominator are of different types or of the
same nonintegral type, ghci
complains:
ghci>
3.14 % 8
<interactive>:1:0: Ambiguous type variable `t' in the constraints: `Integral t' arising from a use of `%' at <interactive>:1:0-7 `Fractional t' arising from the literal `3.14' at <interactive>:1:0-3 Probable fix: add a type signature that fixes these type variable(s)ghci>
1.2 % 3.4
<interactive>:1:0: Ambiguous type variable `t' in the constraints: `Integral t' arising from a use of `%' at <interactive>:1:0-8 `Fractional t' arising from the literal `3.4' at <interactive>:1:6-8 Probable fix: add a type signature that fixes these type variable(s)
Although it is initially useful to have
:set +t
giving us type
information for every expression we enter, this is a facility we will
quickly outgrow. After a while, we will often know what type we expect
an expression to have. We can turn off the extra type information at any time, using the
:unset command:
ghci>
:unset +t
ghci>
2
2
Even with this facility turned off, we can still get that type information easily when we need it, using another ghci command:
ghci>
:type 'a'
'a' :: Charghci>
"foo"
"foo"ghci>
:type it
it :: [Char]
The :type command will print type information for any expression we give it
(including it
, as we see here). It won’t actually
evaluate the expression; it checks only its type and prints that.
Why are the types reported for these two expressions different?
ghci>
3 + 2
5ghci>
:type it
it :: Integerghci>
:type 3 + 2
3 + 2 :: (Num t) => t
Haskell has several numeric types. For
example, a literal number such as 1
could, depending on the context in which it appears, be an integer or a
floating-point value. When we force ghci to evaluate the expression 3 +
2
, it has to choose a type so that it can print the value, and it
defaults to Integer. In the second case, we ask ghci to print the type of the expression
without actually evaluating it, so it does not have to be so specific.
It answers, in effect, “its type is numeric.” We will see more of this
style of type annotation in Chapter 6.