Week 7: Notes

tuples
where
standard type classes
numeric type classes
type conversions
list comprehensions

You can read about these subjects in Learn You a Haskell, chapters 1-4.

infinite lists

A range can be infinite. For example, here is a list of integers from 1 to ∞:

> ints = [1..]

The built-in function take will take only the first N elements of a list for a given N. It is convenient for looking at the first values of an infinite list:

> take 10 ints
[1,2,3,4,5,6,7,8,9,10]

As an alternative to Haskell's range syntax, we can write a function to generate an infinite list of numbers:

intsFrom :: Integer -> [Integer]
intsFrom x = x : intsFrom (x + 1)

For example:

> take 10 (intsFrom 1)
[1,2,3,4,5,6,7,8,9,10]

We can use a similar technique to generate an infinite list of Fibonacci numbers:

fibsFrom :: Integer -> Integer -> [Integer]
fibsFrom i j = i : fibsFrom j (i + j)

Let's try it:

> take 15 (fibsFrom 1 1)
[1,1,2,3,5,8,13,21,34,55,89,144,233,377,610]

Notice that in each of the examples above, our function produced one list element, then called itself recursively to generate the rest of the list.

We can even define an infinite list using a recursive variable definition:

> ones = 1 : ones
> take 10 ones
[1,1,1,1,1,1,1,1,1,1]

type defaulting

In Haskell, even numeric literals are polymorphic:

> :t 2
2 :: Num a => a
> :t 3.5
3.5 :: Fractional a => a

We see that 2 may have any type that's an instance of the Num type class (e.g. Int, Integer, Float, Double). Similarly, 3.5 may have any type that's an instance of Fractional (e.g. Float, Double). We may choose any compatible type that we like:

> 2 :: Integer
2
> 3.5 :: Float
3.5

Even when we combine literals using operators, the result may still be polymorphic:

> :t (2 + 2)
(2 + 2) :: Num a => a
> :t (2 + 3.5)
(2 + 3.5) :: Fractional a => a

However in some situations Haskell must choose a type. For example, suppose that we actually perform the addition:

> 2 + 2
4
> 2 + 3.5
5.5

What type did Haskell use in the calculation? Its rule is that if it must resolve an ambiguous numeric type, it will use the first of these types that is possible: Integer, Double. Thus, the first addition above was performed using values of type Integer, and the second used type Double.