fp1 Print
fp1 Print
***
Functional Programming and
Interactive Theorem Proving
Ulrich Berger
Michaelmas Term 2007
2
***
***
MMISS:
3
MMISS:
4
Recommended Books
• Graham Hutton. Functional Programming in Haskell, Cambridge
University Press, 2006.
• Kees Doets and Jan van Eijck. The Haskell Road to Logic, Maths an
Programming, King’s College Publications, 2004.
MMISS:
5
MMISS:
6
• The course web page (contains more links to useful web pages)
http://www.cs.swan.ac.uk/~csulrich/fp1.html
• Wikipedia
http://en.wikipedia.org
MMISS:
7
Coursework
• Lab classes: Linux lab (room 2007), Monday 12-1, Tuesday 1-2.
Start: 8/10. Computer accounts will be sent by email.
• Coursework counts 20% for CS-221 and 30% for CS-M36 (part 1).
• CS-221: Courseworks 1,2.
• CSM36 (Part 1): Courseworks 1,2,3.
• Submission via coursework box on the 2nd floor.
• Deadlines:
CW1: 17/10 - 1/11, CW2: 14/11 - 29/11, CW3: 21/11 - 6/12.
MMISS:
8
MMISS:
9
Overview (Part I)
1. Functional programming: Ideas, results, history, future
2. Types and functions
3. Case analysis, local definitions, recursion
4. Higher order functions and polymorphism
5. The λ-Calculus
6. Lists
7. User defined data types
8. Proofs
MMISS:
1 Functional Programming:
Ideas, Results, History, Future
1.1 Ideas 11
1.1 Ideas
Referential Transparancy
MMISS: Ideas
1.1 Ideas 12
• Abstraction
◦ Data abstraction
◦ Function abstraction
◦ Typing
MMISS: Ideas
1.1 Ideas 13
MMISS:
1.2 Results 14
1.2 Results
MMISS:
1.2 Results 15
MMISS:
1.2 Results 17
• Artificial Intelligence
• Scientific computation
• Theorem proving
• Program verification
• Web programming
MMISS:
1.2 Results 18
• XML parser
• Data bases
• Telecommunication
• Graphic programming
• Games
http://homepages.inf.ed.ac.uk/wadler/realworld/
MMISS:
1.2 Results 19
• See http://www.haskell.org/aboutHaskell.html
MMISS:
1.2 Results 20
Example: Quicksort
To sort a list with head x and tail xs, compute
• high = the list of all elements in xs that are greater or equal than x.
Then, recursively sort low and high and append the results putting x in
the middle.
MMISS:
1.2 Results 21
Quicksort in Haskell
qsort [] = []
qsort (x:xs) = qsort low ++ [x] ++ qsort high
where
low = [y | y <- xs, y < x]
high = [y | y <- xs, y >= x]
MMISS:
1.2 Results 22
Quicksort in C
do {
while ((l < h) && (a[l] <= p))
MMISS:
1.2 Results 23
l = l+1;
while ((h > l) && (a[h] >= p))
h = h-1;
if (l < h) {
t = a[l];
a[l] = a[h];
a[h] = t;
}
} while (l < h);
t = a[l];
a[l] = a[hi];
a[hi] = t;
MMISS:
1.2 Results 24
MMISS:
1.3 History 25
1.3 History
• Foundations 1920/30
◦ Combinatory Logic and λ-calculus (Schönfinkel, Curry, Church)
• First functional languages 1960
◦ LISP (McCarthy), ISWIM (Landin)
• Further functional languages 1970– 80
◦ FP (Backus); ML (Milner, Gordon), later SML and CAML; Hope
(Burstall); Miranda (Turner)
• 1990: Haskell
MMISS:
1.4 Future 26
1.4 Future
MMISS:
2 Types and functions
2 Types and functions 28
Contents
• How to define a function
• How to run a function
• Some basic types and functions
• Pairs and pattern matching
• Infix operators
• Computation by reduction
• Type synonyms
• Example
Why types?
A hugs session
We assume that our example programs are written in a file
hugsdemo1.hs (extension .hs required). After typing
hugs
in a command window in the same directory where our file is, we can run
the following session (black = hugs, red = we)
Prelude> :l hugsdemo1.hs
Reading file \"hugsdemo1.hs\":
Hugs session for:
/usr/share/hugs/lib/Prelude.hs
hugsdemo1.hs
Main> dSum 2 3
10
Main> f 2 3
11
Main> f (f 2 3) 6
35
Main> :q
{-
Longer comments
can be included like this
-}
Exercises
• Use p16 to compute the 16th powers of some numbers between 1 and
10. What do you observe? Try to explain.
• Boolean values
• Predefined functions:
not :: Bool -> Bool negation
(&&) :: Bool -> Bool -> Bool conjunction (infix)
(||) :: Bool -> Bool -> Bool disjunction (infix)
3 ^ 4 81
4 ^ 3 64
-9 + 4 -5
-(9 + 4) -13
2-(9 + 4) -11
abs -3 error
abs (-3) 3
div 9 4 2
mod 9 4 1
Comparison operators:
(==),(/=),(<=),(<),(>=),(>) :: Int -> Int -> Bool
-9 == 4 False
9 == 9 True
4 /= 9 True
9 >= 9 True
9 > 9 False
But also
(==),(/=),(<=),(<),(>=),(>) :: Bool -> Bool -> Bool
Exercise
Recall the definition
exOr :: Bool -> Bool -> Bool
exOr x y = (x || y) && (not (x && y))
Example
half :: Int -> Float
half x = x / 2
Does not work because division (/) expects two floating point numbers
as arguments, but x has type Int.
Solution:
half :: Int -> Float
half x = (fromIntegral x) / 2
Example
rep :: String -> String
rep s = s ++ s
The letters a and b are type variables, that is, place holders for arbitrary
types (see section on polymorphism).
MMISS: Pairs and pattern matching
2.4 Pairs and pattern matching 57
x ‘exOr‘ y
x ‘dSum‘ y
(&&) x y
(+) 3 4
inc x = x + 1
dSum x y = 2 * (x + y)
f x y = inc (dSum x y)
Evaluation strategy
• From outside to inside, from left to right.
f (inc 3) 4
inc (dSum (inc 3) 4)
(dSum (inc 3) 4) + 1
2*(inc 3 + 4) + 1
2*((3 + 1) + 4) + 1 17
• call-by-need or lazy evaluation
◦ Arguments are calculated only when they are needed.
◦ Lazy evaluation is useful for computing with infinite data structures.
swap :: Pt -> Pt
swap (x,y) = (y,x)
2.8 Exercises
• Define a function average that computes the average of three
integers.
energy x y = x * y * 9.81
three x y z = x ++ y ++ z
MMISS:
3 Case analysis, local
definitions, recursion
3 Case analysis, local definitions, recursion 69
Content
• Recursion
• Layout
• Guarded equations
signum :: Int -> Int
signum x
| x < 0 = -1
| x == 0 = 0
| otherwise = 1
• let
better
• where
or
MMISS: Recursion
3.3 Recursion 76
3.3 Recursion
• Recursion = defining a function in terms of itself.
fact :: Int -> Int
fact n = if n == 0 then 1 else n * fact (n - 1)
Does not terminate if n is negative. Therefore
fact :: Int -> Int
fact n
| n < 0 = error "negative argument to fact"
| n == 0 = 1
| n > 0 = n * fact (n - 1)
MMISS: Recursion
3.3 Recursion 77
Due to two recursive calls this program has exponential run time.
MMISS: Recursion
3.3 Recursion 78
MMISS: Layout
3.4 Layout 79
3.4 Layout
Due to an elaborate layout Haskell programs do not need many brackets
and are therefore well readable. The layout rules are rather intuitive:
• lists of equations and other special constructs must properly line up.
3.5 Exercises
• Define recursively a function euler such that for every nonnegative
integer n and every real number x (given as a floating point number)
n
X xk
euler n x =
k!
k=0
MMISS:
4 Higher order functions and
Polymorphism
4 Higher order functions and Polymorphism 82
Contents
• Function types
• Polymorphic functions
• Lambda abstraction
is shorthand for
• f x1 x2 ... xn
is shorthand for
Sections
If we apply a function of type, say
f :: type1 -> type2 -> type3 -> type4 -> type5
to arguments, say, x1 and x2, then
x1 must have type type1, x2 must have type type2.
and we get
f x1 x2 :: type3 -> type4 -> type5
The expression f x1 x2 is called a section of f.
For example add 5 is a section of add because
add :: Int -> Int -> Int
add 5 :: Int -> Int
MMISS: Higher order functions and polymorphism Label
4.1 Function types 88
iter :: Int -> (Int -> Int) -> Int -> Int
iter n f x
| n == 0 = x
| n > 0 = f (iter (n-1) f x)
| otherwise = error "negative argument to iter"
iter 3 addFive 7
addFive (iter 2 addFive 7)
(iter 2 addFive 7) + 5
addFive (iter 1 addFive 7) + 5
(iter 1 addFive 7) + 5 + 5
addFive (iter 0 addFive 7) + 5 + 5
(iter 0 addFive 7) + 5 + 5 + 5
7 + 5 + 5 + 5 22
• twice and iter are higher-order functions whereas add and the
functions we discussed in previous chapters were first-order functions.
4.2 Polymorphism
Another important difference between the functions
add :: Int -> Int -> Int
add x y = x + y
and
twice :: (Int -> Int) -> (Int -> Int)
twice f x = f (f x)
is that while in the signature of add the type Int was special (we could
not have replaced it by, say, Char), in the signature of twice the type
Int was irrelevant.
Exercise
Check the types of the following expressions and compute their values:
twice square 2
twice twice square 2
Type check:
twice :: (a -> a) -> (a -> a)
twice :: (Int -> Int) -> (Int -> Int)
square :: Int -> Int
2 :: Int
therefore
twice square 2 :: Int
Computation:
(twice square) 2 square (square 2) (square 2)2
(22)2 16
Type check:
twice :: ( a -> a )->( a -> a )
twice :: ((Int->Int)->(Int->Int))->((Int->Int)->(Int->Int))
twice :: (Int->Int)->(Int->Int)
square :: Int->Int
2 :: Int
therefore
twice twice square 2 :: Int
Computation:
((twice twice) square) 2
(twice (twice square)) 2
(twice square) ((twice square) 2)
square (square ((twice square) 2))
(square ((twice square) 2))2
(((twice square) 2)2)2
. . . (((22)2)2)2
. . . 216 = 65536
• Projections
fst :: (a,b) -> a
fst (x,_) = x
• Composition
Exercises
In Haskell’s Prelude.hs the function uncurry is defined slightly
differently:
uncurry :: (a -> b -> c) -> ((a,b) -> c)
uncurry f p = f (fst p) (snd p)
instead of
uncurry f (x,y) = f x y
Prove that the functions curry and uncurry are inverse to each other,
that is
uncurry (curry f) = f
curry (uncurry g) = g
for all f :: (a,b) -> c and g :: a -> b -> c.
Extensionality
Two functions are equal when they are equal at all arguments, that is,
f = f’ if and only if f z = f’ z for all z.
Example: Given f :: Int -> Int, find the least n >= 0 such that
f n <= f (n+1).
nondecreasing :: (Int -> Int) -> Int
nondecreasing f = until nondec inc 0 where
nondec n = f n <= f (n+1)
inc n = n+1
What is the value of nondecreasing f for
f :: Int -> Int
f x = x^2 - 6*x
Exercise
Compute for any function f :: Int -> Int and m >= 0 the maximum
of the values f 0, ..., f m.
maxfun :: (Int -> Int) -> Int -> Int
maxfun f m
|m < 0 = error "negative argument to maxfun"
|m == 0 = f 0
|m > 0 = max (maxfun f (m-1)) (f m)
Here we used the predefined function max.
Hugs> :t True
True :: Bool
Hugs> :t (&&)
(&&) :: Bool -> Bool -> Bool
Hugs> :i Num
-- type class
infixl 6 +
infixl 6 -
infixl 7 *
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
(-) :: a -> a -> a
(*) :: a -> a -> a
negate :: a -> a
MMISS: Higher order functions and polymorphism Label
4.3 Type Classes and Overloading 112
abs :: a -> a
signum :: a -> a
fromIntegral :: (Integral a, Num b) => a -> b
-- instances:
instance Num Int
instance Num Integer
instance Num Float
instance Num Double
instance Integral a => Num (Ratio a)
The section
-- type class
...
says which operations each member of the type class Num has.
The section
-- instances:
...
says which types are member of the type class Num.
The line
class (Eq a, Show a) => Num a where
says that each Num inherits all operations from the type classes Eq and
Show.
The line
fromIntegral :: (Integral a, Num b) => a -> b
says that for any type a in the type class Integral and any type b in
the type class Num there is a function
fromIntegral :: a -> b
Exercise
Find out more about the following type classes:
• Eq
• Show
• Ord
• Integral
4.4 λ-Abstraction
Using λ-abstraction we can create anonymous functions, that is,
functions without name.
For example, instead of defining at top level the test function
f :: Int -> Int
f x = x^2 - 6*x
(which is not of general interest) and then running
Main> nondecreasing f
we may simply run
Main> nondecreasing (\x -> x^2 - 6*x)
In general an expression
\x -> <...>
is equivalent to
let f x = <...>
in f
λ-abstraction is not needed, strictly speaking, but often very handy.
Examples of λ-abstraction
• λ-abstraction in definitions:
square :: Int -> Int
square = \x -> x*x
(instead of square x = x*x)
instead of
MMISS:
5 The λ-Calculus
5 The λ-Calculus 124
Contents
• Historical background
• Syntax
• Operational Semantics
• Some fundamental questions
• Normalisation
• Uniqueness of normal forms
• Reduction strategies
• Universality of the λ-calculus
• Typed λ-calculi
5.2 Syntax
λ-terms are defined by the grammar
M ::= x | (λx M ) | (M N )
Conventions:
Free variables
The set of free variables of a term M , denoted FV(M ), is the set of
variables x in a term that are not in the scope of a λ-abstraction, λx.
Substitution
Substitution: M [N/x] is the result of replacing in M every free
occurrence of x by N , renaming, if necessary, bound variables in M in
order to avoid “variable clashes”.
Instead of M [N/x] some authors write M [x/N ], or M [x := N ].
Example:
((λx . y x)(λy . z y))[(x z) / y] = (λx0.(x z) x0)(λy . z y)
The following literal replacement would be wrong:
((λx . y x)(λy . z y))[(x z) / y] = (λx.(x z) x)(λy . z y)
Reduction
β-reduction means carrying out a β-conversion inside a term, that is
C[(λx M ) N ] → C[M [N/x]]
where C[.] denotes a ‘term context’.
Normal forms
A term is in β-normal form (or normal form, for short), if it cannot be
reduced.
M → M 1 → . . . → Mk → N
for some terms M1, . . . , Mk .
5.5 Normalisation
Not every term has a normal form:
Set ω := λx . x x and Ω := ω ω. Then
Ω = (λx . x x) (λx . x x) → (λx . x x) (λx . x x) → . . .
Hence, Ω has no normal form.
◦ strongly normalising.
∗ @
@
R
@ ∗
M1 M2
@
@
@R
@∗ ∗
M3
Example
In a previous reduction chain we used the ‘rightmost-innermost’, or
‘eager’ reduction strategy.
Now let us reduce the same term M M using ‘leftmost-outermost’, or
‘lazy’ reduction which is the strategy Haskell uses.
Y M =β M (Y M )
But also
x1 : a1, . . . , xn : an ` M : b
Γ, x : a ` x : a
Γ, x : a ` M : b
Γ ` λx M : a → b
Γ`M :a→b Γ`N :a
Γ`MN :b
These rules define the simply typed λ-calculus.
For example
M: a→b
corresponds to Haskell’s
M :: a -> b
Type inference
Haskell and ML use elaborate type inference systems (finding a context
Γ and type a such that Γ ` M : a). Type inference was introduced by
Roger Hindley.
Theorem (Hindley) It is decidable whether a term is typeable. If a term
is typeable, its principal type (that is, most general type) can be
computed.
Exercise: What is the most general type of λf.λg.λx.g(f x)?
MMISS:
6 Lists
6 Lists 154
Contents
• Lists in Haskell
• Recursion on lists
• List comprehension
• Examples
MMISS: Lists
6.1 Lists in Haskell 155
[x1,x2,...,xn] =
x1 : x2 : ... xn : [] =
[1,3,5+4] :: [Int]
[’a’,’b’,’c’,’d’] :: [Char]
[(198845,"Cox"),(203187,"Wu")] :: [(Int,String)]
iter :: Int -> (Int -> Int) -> Int -> Int
iter n f x
| n == 0 = x
| n > 0 = f (iter (n-1) f x)
Alternatively
sumSquares [2,3,4] 29
MMISS: Recursion on lists
6.2 Recursion on lists 166
take
Taking the first n elements of a list (predefined):
reverse
The function reverse is predefined. Here is naive program for reversing
lists:
zip
Transforming two lists into one list of pairs.
Informally:
Informally:
map f [x1, . . . , xn] = [f x1, . . . , f xn]
concat [l1,l2,l3,l4] = l1 ++ l2 ++ l3 ++ l4 ++ []
• Combination of both
Exercise
Make the functions ins and isort polymorphic.
ins :: Ord a => a -> [a] -> [a]
ins x xs = lessx ++ [x] ++ grteqx where
(lessx, grteqx) = span (< x) xs
Examples:
[ x * x | x <- [1..10] ]
• Taking all numbers in a list that are divisible by 3 and squaring them:
General form
Several generators
[E |c1 <- L1, c2 <- L2, ..., test1, ..., testn ]
Example: Quicksort
• Split a list into elements less-or-equal and greater than the first
element,
• sort the parts,
• concatenate the results.
qsort :: Ord a => [a] -> [a]
qsort [] = []
qsort (x:xs) = qsort [ y | y <- xs, y <= x ]
++ [x] ++
qsort [ y | y <- xs, y > x ]
Filtering elements
filter :: (a -> Bool) -> [a] -> [a]
filter p xs = [ x | x <- xs, p x ]
or
filter p [] = []
filter p (x:xs)
| p x = x : (filter p xs)
| otherwise = filter p xs
Exercises
What are the values of the following expressions?
[x | x <- [1..10], x > 5]
Exercises
• Determine the values of the following expressions (we use the
predefined function even :: Int -> Bool).
map even [1..10]
filter even [1..10]
(sum . filter even) [1..10]
• Define a function that selects from a list of integers all elements that
are even and smaller than 10.
• Define a function that takes a list [x1, x2, ..., xn] and returns
[(x1, x2), (x2, x3), ...(xn−1, xn)].
MMISS: Examples
6.5 Examples 197
6.5 Examples
More examples on programming with lists:
• Shopping baskets
• Modelling a library
• Forward composition
• Computing an Index
MMISS: Examples
6.5 Examples 198
Shopping baskets
MMISS: Examples
6.5 Examples 199
or
MMISS: Examples
6.5 Examples 200
Modelling a library
type Person = String
type Book = String
type DBase = [(Person, Book)]
MMISS: Examples
6.5 Examples 201
MMISS: Examples
6.5 Examples 202
• Exercises
MMISS: Examples
6.5 Examples 203
MMISS: Examples
6.5 Examples 204
MMISS: Examples
6.5 Examples 205
Forward composition
MMISS: Examples
6.5 Examples 206
p
• Example: the length of a vector. |[x1, . . . , xn]| = (x21 + . . . + x2n).
MMISS: Examples
6.5 Examples 207
Computing an index
• Problem: Given a text
John Anderson my jo, John,\nwhen we were first aquent,
\nyour locks were like the raven,\nyour bonnie brow as
bent;\nbut now your brow is beld, John,\nyour locks are
like the snow;\nbut blessings on your frosty pow,\nJohn
Anderson, my jo. (Robert Burns 1789)
produce for every word the list of lines were it occurs:
[([8],"1789"),([1,8],"Anderson"),([8],"Burns"),([1,1,5,8],"John"),
([8],"Robert"),([2],"aquent"),([5],"belt"),([4],"bent"),
([7],"blessings"),([4],"bonnie"),([4,5],"brow"),([2],"first"),
([7],"frosty"),([3,6],"like"),([3,6],"locks"),([3],"raven"),
([6],"snow"),([2,3],"were"),([2],"when"),([3,4,5,6,7],"your")]
MMISS: Examples
6.5 Examples 208
• Specification
MMISS: Examples
6.5 Examples 209
(c) Split lines into words (keeping the line number) [(Int, Wor)]
MMISS: Examples
6.5 Examples 210
• Main program:
MMISS: Examples
6.5 Examples 211
MMISS: Examples
6.5 Examples 212
MMISS: Examples
6.5 Examples 213
\pagebreak
MMISS: Examples
6.5 Examples 214
◦ Sort by words:
MMISS: Examples
6.5 Examples 215
MMISS: Examples
6.5 Examples 216
Alternative definition:
MMISS:
7 Algebraic data types
7 Algebraic data types 218
Contents
• Simple data
• Composite data
• Recursive data
• The data type Bool contains exactly the constructors False and True.
• The expression ‘deriving(Eq, Show)’ puts Bool into the type classes
Eq and Show using default implementations of ==, /= and show.
Pattern matching
Example: Testing whether a day is a work day
• or guarded equations
• Using enumeration
Summary
• Data types defined in this way are called algebraic data types.
• Names of data types and constructors begin with an upper case letter.
Creating circles
A circle with center p and radius r:
Creating rectangles
A rectangle is given by its bottom left and top right corner (we list the
corners clockwise).
Rotating points
Our next goal is to create a regular polygon with n corners and ‘radius’
r. For this, we need a program that rotates a point around the origin
(anticlockwise).
type Angle = Float
Shifting shapes
Shifting a shape:
addPt :: Pt -> Pt -> Pt
addPt (x1,y1) (x2,y2) = (x1+x2,y1+y2)
Scaling shapes
scalePt :: Float -> Pt -> Pt
scalePt z (x,y) = (z * x, z * y)
Summary
• Using the data keyword the user can introduce new structured data.
• In a data type declaration
data DataType = Constr Type1 ... Typen | . . .
the type of the constructor is
Constr :: Type1 -> ... -> Typen -> DataType
Binary Trees
A binary tree is
• either empty,
Examples of trees
tree0 = Null
Balanced trees
Creating balanced trees of depth n with label indicating depth of node:
Structural recursion
The definitions of member, preorder, inorder, postorder are
examples of
structural recursion on trees
The pattern is:
• Step. Define the function for a composite tree using recursive calls to
the left and right subtree.
Ordered trees
A tree Node l x r is ordered if
Example:
Regions
We define a recursive data type Region that contains shapes as basic
objects and has constructors for rotation and boolean combinations of
regions:
data Region = Sh Shape
| Rotate Float Region
| Inter Region Region
| Union Region Region
| Compl Region
| Empty
then we have
Examples of regions
A ring with outer radius 1.5 and inner radius 1:
A tree:
Operations on Regions
Shifting:
Summary
• Using the data keyword the user can introduce new recursive data
types
Exercises
MMISS:
8 Proofs
8 Proofs 261
Contents
• Verifying recursive programs by induction
• Timing analysis
MMISS: Proofs
8.1 Verifying recursive programs by induction 262
◦ induction on lists;
◦ induction on trees.
• Example:
f :: Int -> Int
f n = if n == 0 then 0 else f (n-1) + n
Show that for all natural numbers n (that is, integers n ≥ 0) the
equation f n = n∗(n+1)
2 holds.
◦ Base: f 0 = 0 = 0∗(0+1)
2 .
◦ Step: Assume f n = n∗(n+1)
2 (i.h.).
We have to show f (n + 1) = (n+1)∗(n+2)
2 .
i.h. n ∗ (n + 1)
f (n + 1) = f n + (n + 1) = +n+1=
2
n ∗ (n + 1) + 2 ∗ (n + 1) (n + 1) ∗ (n + 2)
= =
2 2
MMISS: Recursion induction
8.1 Verifying recursive programs by induction 265
Induction on lists
• In order to prove
• Example:
((x:xs) ++ ys) ++ zs
= (x : (xs ++ ys)) ++ zs (by def. of (++))
= x : ((xs ++ ys) ++ zs) (by def. of (++))
= x : (xs ++ (ys ++ zs)) (by i.h.)
= (x:xs) ++ (ys ++ zs) (by def. of (++))
• Exercises
◦ Prove xs ++ [] = xs
◦ Recall
Induction on trees
data Tree a = Null
| Node (Tree a) a (Tree a)
• In order to prove
• Example:
height :: Tree a -> Int
height Null = 0
height Node xt _ yt = 1 + max (height xt) (height yt)
• Base:
length (preord Null) = length [] = 0 = 2^(height Null) - 1.
• Step: Assume
length (preord xt) <= 2^(height xt) - 1
and
length (preord yt) <= 2^(height yt) - 1 (i.h.).
We have to show
length(preord(Node xt x yt)) <= 2^(height(Node xt x yt))-1
for all x.
MMISS: Recursion induction
8.1 Verifying recursive programs by induction 273
MMISS: Proofs
8.2 Timing analysis 274
n ∗ (n + 3)
+1
2
reductions, where n is the length of the list.
◦ Base:
reverse [] [] (one step).
0 ∗ (n + 3)
+1=1
2
◦ Step:
n ∗ (n + 3) (n + 1) ∗ (n + 4)
1+( + 1) + (n + 1) = . . . = +1
2 2
For example
takeTree 1 (Node xt x yt)
take 1 (preord (Node xt x yt))
take 1 ([x] ++ preord xt ++ preord yt)
take 1 (x : (preord xt ++ preord yt))
x : take 0 (preord xt ++ preord yt) [x]
Exercises
MMISS:
9 Abstract Data Types
9 Abstract Data Types 290
Contents
• The concept of an Abstract Data Type (ADT)
MMISS: Modules
9.2 Implementation of ADTs by modules 292
MMISS: Modules
9.2 Implementation of ADTs by modules 293
module Store(
Store,
initial, -- :: Store a b
value, -- :: Eq a => Store a b -> a -> Maybe b
update, -- :: Eq a => Store a b -> a -> b -> Store a b
) where
initial :: Store a b
initial = []
MMISS: Modules
9.2 Implementation of ADTs by modules 296
MMISS: Modules
9.2 Implementation of ADTs by modules 297
• The complete code for the module (interface + body) must be written
in the file Store.hs (capital S!).
Importing a module
• import Name (identifiers)
◦ The identifiers declared in module Name are imported.
◦ If (identifiers) is omitted, then everything is imported.
MMISS: Modules
9.2 Implementation of ADTs by modules 300
initial :: Store a b
initial = \_ -> Nothing
MMISS: Modules
9.2 Implementation of ADTs by modules 301
MMISS: Sets
9.3 The ADT of Sets 302
6. Extensionality: Two sets s, t are equal when they contain the same
elements, that is, an element is a member of s if and only if it is a
member of t:
s = t ⇐⇒ ∀x(x ∈ s ↔ x ∈ t)
We do not (yet) require a test for deciding equality of sets.
MMISS: Sets
9.3 The ADT of Sets 304
Implementation of sets
MMISS: Sets
9.3 The ADT of Sets 305
Sets – Interface
module Set (
Set, -- type constructor
empty, -- Set a
insert, -- Eq a => a -> Set a -> Set a
member, -- Eq a => a -> Set a -> Bool
union, -- Eq a => Set a -> Set a -> Set a
sfilter -- Eq a => (a -> Bool) -> Set a -> Set a
) where
MMISS: Sets
9.3 The ADT of Sets 306
empty :: Set a
empty = \x -> False
MMISS: Sets
9.3 The ADT of Sets 307
MMISS: Sets
9.3 The ADT of Sets 308
empty :: Set a
empty = []
member x xs = elem x xs
MMISS: Sets
9.3 The ADT of Sets 310
MMISS: Sets
9.3 The ADT of Sets 311
MMISS: Sets
9.3 The ADT of Sets 312
MMISS: Sets
9.3 The ADT of Sets 313
• Can we
• On the other hand there are no problems with the list implementation:
MMISS: Sets
9.3 The ADT of Sets 314
MMISS: Sets
9.3 The ADT of Sets 315
MMISS: Sets
9.3 The ADT of Sets 316
MMISS: Modules
9.4 Minimality versus Efficiency 318
• The interface of our first ADT of sets was minimal in the sense that
we omitted a function if it could be defined by other functions (for
example singleton, delete, meet, minus were defined in this way).
• For example, our definition of meet has time complexity O(n2), but if
sets are represented by ordered lists one can achieve linear time:
MMISS: Modules
9.4 Minimality versus Efficiency 320
Without ordering:
meet2 :: Eq a => [a] -> [a] -> [a]
meet2 xs ys = [x | x <- xs, x ‘elem‘ ys]
MMISS: Modules
9.4 Minimality versus Efficiency 321
Summary
• An abstract data type (ADT) consists of one or more data types
together with some functions. Details of how data are constructed and
functions are defined are hidden.
• Abstract data types support modularization and make code more
robust: The implementation of an ADT may change without other
programs using it being affected.
• An important abstract data type is the ADT of sets. Sets can be
represented in different ways allowing for implementations of different
operations.
• The choice of representation of may also affect the efficiency of set
operations.
MMISS: Modules
9.4 Minimality versus Efficiency 322
Exercises
MMISS:
10 Input/Output
10 Input/Output 324
Contents
• Input/Output in functional languages
• Actions as values
• Random numbers
MMISS: Input/Output
10.1 Input/Output in functional languages 325
• Solution:
Side effects are marked by IO — actions
◦ Actions can be combined with actions only
◦ once IO, always IO“
”
MMISS: Input/Output
10.1 Input/Output in functional languages 326
The type IO a
MMISS: Input/Output
10.1 Input/Output in functional languages 327
MMISS: Input/Output
10.1 Input/Output in functional languages 328
• If we are given
action1 :: IO a
action2 :: a -> IO b
first does action1 and then action2 x where x is the value returned
by action1.
MMISS: Input/Output
10.1 Input/Output in functional languages 329
MMISS: Input/Output
10.1 Input/Output in functional languages 330
A simple example
• Echo:
echo :: IO ()
echo = getLine >>= putStrLn >>= \_ -> echo
• Reversed echo:
ohce :: IO ()
ohce = getLine >>= putStrLn . reverse >> ohce
where (>>) is predefined:
(>>) :: IO a -> IO b -> IO b
f >> g = f >>= \_ -> g
MMISS: Input/Output
10.1 Input/Output in functional languages 331
“First do f, then g,
MMISS: Input/Output
10.1 Input/Output in functional languages 332
The do-notation
MMISS: Input/Output
10.1 Input/Output in functional languages 333
Note that the only way to modify and use the storage is via the functions
update and value provided by the ADT Store.
MMISS: Input/Output
10.1 Input/Output in functional languages 334
import Store
notebook :: IO ()
notebook = loop initial where
loop :: Store String String -> IO ()
loop st =
do s <- getLine
case words s of
"u":name:value:_ -> loop (update st name value)
"v":name:_ ->
do putStrLn (case value st name of
Just val -> val
Nothing -> "Unknown: "++name)
loop st
_ -> return ()
MMISS: Input/Output
10.2 Communication with files 335
MMISS: Input/Output
10.2 Communication with files 336
MMISS: Input/Output
10.3 Actions as values 337
MMISS: Input/Output
10.3 Actions as values 338
MMISS: Input/Output
10.4 Random numbers 340
MMISS: Input/Output
10.4 Random numbers 341
• Random string:
randomStr :: IO String
randomStr = atmost 10 (randomRIO (’a’,’z’))
MMISS: Input/Output
10.4 Random numbers 342
Roulette
• Start with 100 pounds.
MMISS: Input/Output
10.4 Random numbers 343
We use a variant of until that accepts a next function with side effects:
untilIO :: (a -> Bool) -> (a -> IO a) -> a -> IO a
untilIO stop next x =
if stop x
then return x
else do x1 <- next x
untilIO stop next x1
Compare this with
until :: (a -> Bool) -> (a -> a) -> a -> a
until stop next x =
if stop x
then x
else let x1 = next x
in until stop next x1
MMISS: Input/Output
10.4 Random numbers 344
roulette :: IO ()
roulette =
do putStr "You have 100 pounds. Which number do you choose? "
n <- getLine
putStr "How many rounds do you want to play maximally? "
r <- getLine
let mine = read n :: Int
maxRounds = read r :: Int
stop (k,money) = k >= maxRounds || money <= 0
next (k,money) = do x <- randomRIO (0,36)
let win = if x == mine then 36 else 0
return (k+1, money - 1 + win)
(rounds,endMoney) <- untilIO stop next (0,100)
putStr ("\nYou played "++(show rounds)++" rounds " ++
"and have now "++(show endMoney)++" pounds")
MMISS: Input/Output
10.4 Random numbers 345
Summary
• Input/Output in Haskell by Actions
◦ Actions (type IO a) are functions with side effects
◦ Combination of actions by
(>>=) :: IO a -> (a -> IO b) -> IO b
return :: a -> IO a
◦ do-Notation
• Various functions from the standard library:
◦ Prelude: getLine, putStr, putStrLn, writeFile, readFile
◦ Modules: IO, Random,
MMISS: Input/Output
10.4 Random numbers 346
MMISS: Input/Output
10.4 Random numbers 347
Exercises
• Write an interactive translation program, say from English to French
and vice versa. Use a dictionary of the form
[(apple,pomme),(street,rue),(sun,soleil),...].
• Modify the program saveCW such that the statistical data are written
to the file as well.
• Modify the program roulette such that after each 100 rounds the
player is informed about their current account and given the choice
whether or not to continue.
MMISS:
11 Infinite lists
11 Infinite lists 349
Contents
• Corecursion
MMISS: Infinite-lists
11 Infinite lists 350
MMISS: Infinite-lists
11 Infinite lists 352
MMISS: Infinite-lists
11 Infinite lists 353
For example
iterate (+3) 0 = 0 : iterate (+3) 3
= 0 : 3 : iterate (+3) 6
= 0 : 3 : 6 : iterate (+3) 9
...
Hence
iterate (+3) 0 = [0,3,6,9,...]
MMISS: Infinite-lists
11 Infinite lists 354
MMISS: Infinite-lists
11 Infinite lists 355
MMISS: Infinite-lists
11 Infinite lists 356
Corecursion
The recursive definitions of infinite lists we have seen follow a common
pattern:
xs = ... : ... xs ...
This pattern is called corecursion:
This means an infinite list xs is produced by
MMISS: Infinite-lists
11 Infinite lists 357
MMISS: