# Types and functions, continued

In this session we further consider the relationship between types and functions.

We’ll start by considering the following expression, which reads similarly to English.You cannot type this expression directly into GHCi because it has a variable `x` that we have not bound anywhere – but we will get to that.

``if (x < 10) then (negate x) else (x + 10)``

If x is less than ten, then we will negate x; otherwise, we will add ten.

Each part of this has a type.

## Types of subexpressions

First let’s consider just the `x < 10` part.

`10` is a number, and we’re comparing `x` to `10`. This should lead us to conclude that `x` also has to be a number; numbers have to be compared to other numbers.

So, if `x` is some number, then this expression `x < 10` will return a `Bool` value. The comparison returns `True` or `False`; is x less than ten, or is it not?

If `x < 10` is `True`, then we will take the `then` branch and negate x. What should the type of `negate x` be?

The `negate` function changes the sign of a number.

• If `x` is one (`1`), then `negate x` is negative one (`-1`).
• If `x` is negative one (`-1`), then `negate x` is one (`1`).

The output from negating a number is the same type of number as the input. The `negate` function takes a number, and returns another number of the same type.

Similarly, `x + 10` has a type.

Again, we have an operation involving the number `10`, so there are numbers involved. `x` must be a number to be added to ten. But unlike `x < 10` which produced a yes/no, `x + 10` outputs a number – specifically, the same type of number that `x` is.

## What type of number?

We previously talked about how there are different types of numbers. So what type of number are we dealing with in this expression?

You might be thinking – well, `10` looks like a really solid whole number – it’s probably an integer. But don’t be misled by the way the number is written. There are plenty of other ways to write the number ten, some of which certainly appear fractional:

``````λ> 10 == 10.0
True

λ> 10 == 10/1
True``````

Even though we’ve written ten as `10` in the if-then-else expression and not `10.0`, we could still allow `x` to be, for example, `5.5` – and that would work fine with this expression.

So, what is the type of the entire expression?

Whatever type of number `x` is, that’s the type of the whole expression. But we still haven’t settled on a more specific answer.

## Constrained polymorphism

We don’t know what type that is, and we don’t need to know. What we have here is called a polymorphic expression. That means that the function’s input can take on different types, and its output can take on different types of different types (although in this case, the input and output have to be the same as each other).

We talked about how there’s a typeclass called `Num`. Since `x` has to be a number, but we don’t want to pin down specifically what type of number, we can write our type declaration like this:Here we have taken the expression above and put it in the context of a named function. This allows us to bind the variable `x` as a parameter of the function, and gives us the opportunity to write a type declaration for the function.

``````idk :: (Num a) => a -> a
idk x =
if (x < 10) then (negate x) else (x + 10)``````

We have a variable named `a` in our type declaration, and this variable is constrained by the `Num` typeclass. In this type we are asserting:

• That `a` is a type of number (by the constraint `Num a =>`)
• That the input and output have to be the same type of number (because the variable `a` appears twice in `a -> a`; we did not, for example, write `a -> b`, which would allow the two types `a` and `b` to differ).

What we’ve written so far isn’t quite right yet.

## The Ord class

The `negate` and `+` functions come from the `Num` typeclass, and so from that we inferred that `a` needs a `Num` constraint. But the `<` function comes from a different class, called `Ord`.

To get information about types and typeclasses, you can use the `:info` command in GHCi. Let’s try that out now.

``````λ> :info Ord
class Eq a => Ord a where
compare :: a -> a -> Ordering
(<) :: a -> a -> Bool
(<=) :: a -> a -> Bool
(>) :: a -> a -> Bool
(>=) :: a -> a -> Bool
max :: a -> a -> a
min :: a -> a -> a
...``````

This prints a lot of information – more than we need – so you’ll probably need to scroll back up in your terminal to read it from the beginning, and here we’ve truncated the output for brevity’s sake.

The first line `class Eq a => Ord a where` and the indented lines immediately below it comprise the typeclass definition. We can see here all of the functions in the `Ord` class: `compare`, `<`, `<=`, `>`, `>=`, `max`, and `min`.

Recall that many types are orderable, such as characters (`'a'` comes before `'b'`), which aren’t numbers. So `Ord` is a different typeclass than `Num`, because some things are orderable that are not numbers.

So that means we need to add a second constraint on the type variable `a`. Whatever type of number `x` turns out to be, it has to be both:

• A number, so that it can be negated, compared with ten, and added to ten;
• Something that is orderable, so that it can be compared.

## Try it out

Make sure the code is loaded into your REPL session, and try using the function.

``````λ> :load main.hs

λ> idk 4
-4``````

Four is less than ten, so 4 is negated to produce -4.

When we apply the function to a bigger number, the `else` branch applies:

``````λ> idk 120
130``````

Ten is added to 120, and we get 130.

We have this nice polymorphic function that we can use with things other than integers, so let’s make sure we try that out as well.The answer we see here is slightly off due to rounding error in this number’s binary representation. This is one of the reasons there are many types of numbers: in some applications, small roundoffs are acceptable; in others, they are not.

``````λ> idk 12.13
22.130000000000003``````

To enter a number fractionally, be sure to write the fraction in parentheses to ensure that the division happens first.

``````λ> idk (12/5)
-2.4``````

`12/5` is `2.4`, so the result we got back was its negation.

So, to recap this lesson: We have seen how an expression is composed of subexpressions, and every expression has a type. `x` and `10` are numbers, `x < 10` is a Boolean true/false, `negate x` has the same type as `x`, and `x + 10` does as well. Finally, the if-then-else expression as a whole also has a type – the same type as `x`.

## Exercise

``preferJ x y = if (elem 'j' x) then x else y``

We saw this `elem` function briefly before.

Try to write a type declaration for the `preferJ` function. First, think through what the types of all the subexpressions must be.

• What is the type of `elem 'j' x`?
• What are the types of `x` and `y`?
• Then, finally, what is the type of `preferJ`?

The type declaration you write for `preferJ` will look a little different from `idk`:

• It may be concrete, not polymorphic (in other words, it does not need any constraints or the `=>` arrow).
• This function has two parameters, not one, so it will need two `->` arrows.

Join Type Classes for courses and projects to get you started and make you an expert in FP with Haskell.