Can a program tell you it is wrong before it runs?
A spreadsheet that adds a name to a number gives a strange answer, and you find out later. Haskell asks you to say what kind of thing each function takes and gives back, and checks that before anything runs. Then a whole class of mistakes cannot happen.
By the end of this lesson
Note
I can read and run a Haskell function and say what its type tells me.
Key words
- Function: something that takes a value and gives a value back.
- Type: the kind of value, such as
Intfor a whole number orStringfor text. - Type signature: the line that gives a function its type, such as
square :: Int -> Int. - List: several values of one type in order, written
[1, 2, 3]. - Fold: a way to combine every item of a list into one value.
Starter: what you already know
Note
Answer in your head. 1. In maths, if f(x) = x * x, what is f(5)? 2. Is 7 the same kind of thing as "seven"? 3. What is the sum of the list 1, 2, 3? Answers: 25; no, one is a number and the other is text; 6.
Before you start
Note
Press Start the lab on the bar at the top of this lesson and wait until it says it is running. There is one container, haskell. Nothing opens in a browser, so use the terminal, where docker exec haskell runs one command inside it. The compiler takes a couple of seconds to start each time. Everything printed is in English, whatever language this page is in. Each Run button below types its command into your lab's terminal, one after another in the same session. To watch them, or to type your own, press Open terminal on the bar.
A function has a type signature
This prints the first file. The line square :: Int -> Int is a type signature. Read it as "square takes an Int and gives back an Int". The next line says how: square n = n * n. A function has no side effects here: give it the same value and you get the same answer. -- starts a comment.
docker exec haskell cat Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run a file, or ask about one function
runghc runs the file. Its main prints three lines: Hello, Haskell!, then 49, then (True,False). The ghc -e options work out one expression with the file loaded: the first asks for the type of square and prints square :: Int -> Int, and the second calls it and prints 144.
docker exec haskell runghc Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
docker exec haskell ghc -e ":type square" Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
docker exec haskell ghc -e "square 12" Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Check
Tip
What does isEven :: Int -> Bool tell you before you read the code? Answer: it takes a whole number and gives back True or False.
A list is worked on with functions
map applies a function to every item and filter keeps the items that pass a test. The first command squares 1 to 5 with square and adds them up with sum: it prints 55. The second keeps the even numbers from 1 to 10 and prints [2,4,6,8,10]. Neither changes the original list: each gives a new value.
docker exec haskell ghc -e "sum (map square [1 .. 5])" Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
docker exec haskell ghc -e "filter even [1 .. 10]"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A function can call itself, and a fold does it for you
mySum in Fold.hs adds a list by adding the first item to the sum of the rest, and stopping at the empty list. This prints 6. The second command does the same job with the built-in foldr, which folds a list into one value: it prints 5050, the sum of 1 to 100.
docker exec haskell ghc -e "mySum [1, 2, 3]" Fold.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
docker exec haskell ghc -e "foldr (+) 0 [1 .. 100]"Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
The compiler checks the types
This gives square some text instead of a number. Nothing runs. The compiler prints an error that starts with <interactive> and says it could not match the type [Char], which is text, with Int. Read the error from the top: it names the part of your expression that is wrong. The code in brackets and the layout can differ between versions.
docker exec haskell ghc -e "square \"two\"" Basics.hsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
A common mistake
Warning
Many people think a type signature is only a comment for the reader. It is not. The compiler checks every one, and if the code does not match, nothing runs at all. Write the signature first when you can: it says what you meant, and the compiler tells you when the code says something else.
Exit check
Tip
Answer without looking back. 1. What does Int -> Bool mean? 2. What does filter even [1 .. 10] give? 3. When does the compiler find a type error: before the program runs or after? 4. What does a fold do to a list? Answers: takes a whole number and gives True or False; [2,4,6,8,10]; before, so nothing runs; it combines every item into one value.
For teachers
Tip
This lesson is a small example of a lesson worked in a lab: the steps and the Run buttons are the lesson, and the lab is each student's own copy. The lab is one container with the GHC compiler and four small files, and nothing here marks itself: the student hands in the expressions they tried and what each printed, a function of their own with its type and a call that shows it, and a sentence on what a type signature tells the reader. Key learning points: 1. A function takes a value and gives one back. 2. A type signature says what a function takes and gives. 3. Lists are worked on with functions such as map and filter. 4. A function can call itself, and a fold does the same job. 5. The compiler checks types before anything runs. Common mistake: treating a signature as a comment. Equipment: the lab and its terminal. Tip: ask students to write the type of a function before they write its body. Every answer is exact and the same each time; the first command after a start takes a couple of seconds. Names and messages are in English, whatever language the page is in. Copy it into your own module and change it, or build one from scratch with the Lab menu in the lesson builder.