What is a function with a type?
Haskell is a functional programming language. A program is built from functions, and every function has a type that says what it takes and what it gives back.
This matters because the type catches many mistakes before the program runs. In this lesson you read small functions that work out prices and learn what each type tells you.
By the end of this lesson
Note
I can read a small Haskell function and say what its type means.
Key words
| Word | What it means | Example |
|---|---|---|
| Function | something that takes values in and gives a value back | |
| Pure function | a function whose answer depends only on what it is given | |
| Type | the kind of value, such as a whole number or text | Int |
| Type signature | the line that says what a function takes and gives back | addVat :: Int -> Int |
| Composition | joining two functions so the output of one feeds the next | f . g |
The cells students fill in are left blank in this preview.
A function takes values and gives one back
Here is a function for a shop. addVat takes a price in pence and gives back the price with a fifth added. Its first line, with ::, is the type signature.
You call a function by writing its name, a space, then its arguments. There are no brackets and no commas. addVat 1000 means "apply addVat to 1000".
The shop file: two functions and their types
addVat :: Int -> Int
addVat pence = pence + div pence 5
discount :: Int -> Int -> Int
discount percent pence = pence - div (pence * percent) 100
Save the shop file
docker exec haskell sh -c "printf '%s\n' 'addVat :: Int -> Int' 'addVat pence = pence + div pence 5' '' 'discount :: Int -> Int -> Int' 'discount percent pence = pence - div (pence * percent) 100' > Shop.hs"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Add VAT to 1000 pence
docker exec haskell ghc -e "addVat 1000" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Take 10 percent off 2000 pence
docker exec haskell ghc -e "discount 10 2000" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: addVat 1000, step by step
| Step | Expression | Value |
|---|---|---|
| 1 | pence | 1000 |
| 2 | div pence 5 | 200 (whole-number division) |
| 3 | pence + div pence 5 | 1200 |
The cells students fill in are left blank in this preview.
A type signature shows inputs and output
Read addVat :: Int -> Int as "addVat takes an Int and gives back an Int". An Int is a whole number. Other types are String, for text, and Bool, for True or False.
With two arguments, the signature has more arrows. Int -> Int -> Int takes two Ints and gives back an Int. The last type is always the answer.
Ask GHC for the type of addVat
docker exec haskell ghc -e ":type addVat" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Ask GHC for the type of discount
docker exec haskell ghc -e ":type discount" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Give discount only one argument
docker exec haskell ghc -e ":type discount 10" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A pure function always gives the same answer
A pure function depends only on what it is given and changes nothing else. Call addVat 1000 today, tomorrow or a million times and you get 1200.
That makes a pure function easy to test and easy to trust. You can also join pure functions. Composition is written with a dot: f . g applies g first, then f.
Call the same function twice and compare
docker exec haskell ghc -e "addVat 1000 == addVat 1000" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Discount first, then add VAT
docker exec haskell ghc -e "(addVat . discount 10) 2000" Shop.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Worked example: addVat after discount 10
| Step | Function | Value |
|---|---|---|
| 1 | start | 2000 |
| 2 | discount 10 | 1800 |
| 3 | addVat | 2160 |
The cells students fill in are left blank in this preview.
A common mistake
Warning
Many people think a call needs brackets and commas, as in discount(10, 2000). In Haskell a space separates the function from its arguments: discount 10 2000. Brackets only group: addVat (discount 10 2000) applies addVat to the answer of discount.