Functional Programming -- Exercises 1 | TDA452 & DIT142 | LP2 | HT2012 | [Home] |
This document is designed as introduction to Haskell and the interactive Haskell interpreter GHCi. You are supposed to go through this document using a computer. It's meant to be pretty simple stuff - feel free to skip over some exercises.
Exercises after week 1 of the course work perfectly well with pencil and paper, and we set aside some time on Tuesday mornings (9-10 in EA before the lecture) where you can work on these and ask questions.
You are supposed to work through this document in an afternoon. The
most important tasks are to answer questions that look like this:
candela04> ghciWe will underline the text that you as user of ghci have to write. ghci's output will not be underlined.
___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.4, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base-1.0 ... linking ... done. Prelude>Right now, we don't care about the precise meaning of the text in the welcome message, but focus on the last line with the > symbol. The > symbol indicates that ghci is ready to receive a command. We will explain later on what the word Prelude means. The simplest command one can give to ghci is an Haskell expression, given an Haskell expression ghci will evaluate it, and write the result on the screen. Try:
Prelude> 4+5*6After that, as indicated by the > symbol, ghci is ready to take a new command. We can repeat this interaction as many times as we want. Try:
34
Prelude>
Prelude> 4*(8-5)+3
15
Prelude> 3.5/(3+4)*4.5
2.25
Prelude> sin 1.57
1.0
Prelude>
Prelude> 3+5*The first expression contains a syntax error; there is no right operand of the multiplication operator (*). In the second expression we try to divide by zero. Recognizing different kinds of errors and knowing their causes will take some time to learn!:1:4: parse error (possibly incorrect indentation) Prelude>
Prelude> :q Leaving GHCi. candela04>All ghci commands except evaluating an expressions start with a colon :
We have seen how we can use ghci to do simple calculations. But this
is just the beginning. To go further we need to define our own functions.
As a first example we look at the currency conversion
problem described above. If we need to repeatedly convert pounds to SEK
we can define a function that does
this for us. Defining a function consists of a number of steps.
pounds:: Double -> Double
pounds :: Double -> DoubleBefore we can use the definition we have to give it to ghci. Although it is possible to do this directly in ghci, it is more useful to learn how to do this in a seperate file, since this is what we have to do for larger programs.
pounds kr = kr/12.7775
Prelude> :l ex1.hs Compiling Main ( ex1.hs, interpreted ) Ok, modules loaded: Main. *Main>
Main> pounds 1000
78.2626
Main> pounds 12345
966.151
Main> pounds 127775
10000.0
Main>
A shop sells potatoes for 3.50 SEK / Kg. To stimulates large sales, the shop offers a discount of 3 SEK / Kg for the quantity exceeding 10 Kg.Let's call this function price and the parameter v.
We want to define the function that calculates the price.
Main> 3 < 6The result of such a comparison is either True or False. Notice, that smaller than or equal to is written as <=. Now, we can write the definition of price as follows:
True
Main> 3.5 <= 3
False
Main> pounds 4000 > 3*100
True
price :: Double -> DoubleThe Boolean expressions between | and < are called guards. When this function is applied to a particular argument, ghci checks evaluates the guards from top to bottom until it finds one that evaluates to True, after that the right-hand side of the expression is used to calculate the result. If all guards evaluate to False ghci gives an error message.
price v
|v <= 10 = 3.5*v
|v > 10 = 5+3*v
|v > 11 = 5+3*vWhat is the result of applying the function to 9.5, 10.5 respective 11.5?
price vWhat is the now result of applying the function to 9.5, 10.5 respective 11.5?
|v <= 11 = 3.5*v
|v > 10 = 5+3*v
price :: Double -> Double price v |v <= 10 = 3.5*v |otherwise = 5+3*v
Is otherwise a Haskell keyword? What does hoogle say?
When a function is applied to a simple argument (like 5) we don't need parentheses. But if the argument is composed (like 4 +
8) parentheses are needed.
Main> price 7.5
26.25
Main> price 11
38.5
Main> price (4+8)
41.0
Main>
average :: Double -> Double -> Double
average :: Double -> Double -> Double average x y = (x+y)/2
Main> average 5 8
6.5
Main>
Main> 5 `average` 4
4.5
Main> 4 `max` (5 `max` 2)
5
Main> (+) 3 4
7
Main>
Prelude> div 17 5The function mod gives the remainder for integer division:
3
Prelude> div 34 8
4
Prelude> div 5 9
0
Prelude> 4 `div` 2
2
Prelude>
Prelude> 17 `mod` 5
2
Prelude> 34 `mod` 8
2
Prelude> 5 `mod` 9
5
Prelude> mod 4 2
0
Prelude>
Consider the following game:
Think of an whole number greater than one. If its even, divide it by two, otherwise multiply it by three and add one. Stop if the resulting number is one, otherwise repeat the procedure.As example, we start width 10.
If we start with 7 we get: (Check this!)
7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1.
We are interested in the question: Given a number n, how many
numbers are there in the sequence? For n=10, we get 7 numbers (10, 5,
16, 8, 4, 2, 1). For n=7 we get 17 numbers (See above).
Note that we include both the number n we start with and the final
number 1.
How can ghci help us to answer the question? We start with defining a function next that given a number computes the next number in the sequence.
steps :: Int -> IntWe call this a recursive definition. (You should have met this concept before - otherwise ask for a refund on your undergraduate education!) Write the definition in your file. Load it in to ghci, and calculate steps n for several different values of n.
steps n
|n == 1 = 1
|otherwise = steps(next n)+1
numbers :: Int -> [Int]Load the function into ghci and try:
numbers n
|n==1 = [1]
|otherwise = n : numbers(next n)
Main> numbers 10Study the function definition: When n=1 the result is the list [1]. Otherwise we use the operator : , named cons, which constructs a list from an element and a list by placing the element at the top of the list. The result of numbers n is n followed by the list numbers(next n).
[10, 5, 16, 8, 4, 2, 1]
Main> numbers 17
[17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]
Main> numbers 1
[1]
Main>
Now we have defined the function numbers we don't need to define steps anymore because there is a function length in the prelude that calculates the length of a list.
Try:
Main> length [1,6,33,8,7,14]
6
Main> length (numbers 10)
7
Main>