Title: Recursion on Lists
1Recursion on Lists
- Lecture 5,
- Programmeringsteknik del A.
2Lifting the Bonnet
Today, we take a look under the bonnet and see
how functions like sum, , and take are
defined. Recursion is the key it lets us repeat
computations, to process all the list elements in
turn. Even though Haskell provides a rich set of
predefined functions, you will often need to
define your own.
3Pattern Matching on Lists
The most basic way to take a list apart is via
pattern matching. sum 0 sum x x sum
x, y xy But how can we look inside a
list of arbitrary length?
4A Failed Idea
What about sum (xs ys) sum xs sum ys
??? Example 1, 2, 3 1 2, 3 1,
2 3
Can match in more than one way!
5A Unique Way to Represent Lists
Any (nonempty) list xs can be written as xs
y ys in exactly one way! Examples 1
1 1, 2 1 (2 )
1, 2, 3 1 (2 (3 ))
6A Unique Way to Represent Lists
Any (nonempty) list xs can be written as xs
y ys in exactly one way! Examples 1
1 1, 2 1 (2 )
1, 2, 3 1 (2 (3 ))
New notation y ys
Pronounced cons
1
1 (2 )
1(2(3))
7Cons Patterns
Cons () is allowed in patterns! x xs
Matches first element.
Matches remaining elements.
Examples head a -gt a head (x xs) x
tail a -gt a tail (x xs) xs
8Primitive Recursion on Lists
Every list matches or (x xs)
Base case.
Recursive case.
A smaller list.
9Summing a List
sum Int -gt Int sum 0 sum (x xs) x
sum xs
sum 1, 2 sum (1 (2 )) 1 sum (2
) 1 (2 sum ) 1 (2 0) 3
10Quiz
Give a primitive recursive definition of the
function length a -gt Int
11Quiz
Give a primitive recursive definition of the
function length a -gt Int length
0 length (x xs) length xs 1
12Checking for an Element
elem x xs returns True if x is an element of
xs. elem 3 (1 2, 3, 4) returns True if 3
1, or if 3 is an element of 2, 3, 4 elem
x (y ys) xy elem x ys elem x False
Compare elem x xs or xy y lt- xs
13Defining
How can we reduce xsys to a simpler problem?
Reduce ys to a smaller argument?
Reduce xs to a smaller argument?
Compute 1,2,3 (45,6) from 1,2,3 5,
6???
Compute (12,3) 4,5,6 from 2,3
4,5,6??! 2,3,4,5,6
14Defining
() a -gt a -gt a ys ys (x xs)
ys x (xs ys) How many function calls
are required to evaluate 1..1011..100?
1,23 1 (2 3) 1 (2 (
3)) 1 (2 3) 1,2,3
15Quiz
Define reverse a -gt a
x
w
z
y
x
y
z
w
16Quiz
Define reverse a -gt a
x
w
z
y
x
y
z
w
reverse (x xs) reverse xs x reverse
17Sorting
now is the winter of our discontent
discontent is now of our the winter
It used to be said that computers spent more time
sorting than anything else!
18Insertion Sort
sort (x xs) insert x (sort xs) sort
19Insertion
x
y
z
...
u
w
insert x (y ys) xlty x y ys
xgty y insert x ys insert x x
20Sorting Example
insert 3 1, 2 1 insert 3 2 1 2 insert 3
1 2 3 1, 2, 3
sort 3,1,2 insert 3 (sort 1,2) insert 3
(insert 1 (sort 2)) insert 3 (insert 1 (insert
2 (sort ))) insert 3 (insert 1 (insert 2
))) insert 3 (insert 1 2)
21The Type of Sort
What is the type of sort? sort a -gt a
Can sort many different types of data.
But not all!
Consider a list of functions, for example...
22The Correct Type of Sort
sort Ord a gt a -gt a
then sort has this type.
If a has an ordering...
Sort has this type because (lt) Ord a gt a -gt
a -gt Bool
Overloaded, rather than polymorphic.
23The Correct Type of elem
elem x (y ys) xy elem x ys elem x
False
The type of elem is elem Eq a gt a -gt a -gt
Bool because () Eq a gt a -gt a -gt Bool
24Polymorphism vs Overloading
A polymorphic function works in the same way for
every type. (e.g. length, ). An overloaded
function works in different ways for different
types. (e.g. , lt).
25Variations on List Recursion
Key idea The recursive case expresses the result
in terms of the same function on a shorter
list. The base case handles the shortest
possible list. But the possible variations
are many.
26Defining init
Recall init 1, 2, 3 1, 2
x
w
z
y
x
z
y
x
xs
Compare this to tail (x xs) xs
init a -gt a init x init (x xs)
x init xs
Different base case.
27Checking that a List is Ordered
x lt y
x
...
u
z
y
ordered
ordered Ord a gt a -gt Bool ordered (x y
xs) x lt y ordered (y xs) ordered x
True ordered True
More general pattern
28Zip Recursion on Two Arguments
x
...
z
y
a
...
c
b
Both arguments get smaller.
zip (x xs) (y ys) (x, y) zip xs ys zip
ys zip xs What would happen if we
just defined zip ?
Two cases remain.
29Defining take
n
x
...
z
y
n-1
take Int -gt a -gt a take n (x xs) ngt0
x take (n-1) xs take 0 (x xs) take
n
Two base cases
30A Better Way of Sorting
- Divide the list into two roughly equal halves.
- Sort each half.
- Merge the sorted halves together.
31Defining MergeSort
mergeSort xs merge (mergeSort front) (mergeSort
back) where size length xs div 2 front
take size xs back drop size xs
But when are front and back smaller than xs??
32MergeSort with Base Cases
mergeSort mergeSort x x mergeSort
xs size gt 0 merge (mergeSort front)
(mergeSort back) where size length xs div
2 front take size xs back drop size xs
33Merging
x
x lt y?
y
merge 1, 3 2, 4 1 merge 3 2, 4 1 2
merge 3 4 1 2 3 merge 4 1
2 3 4 1,2,3,4
34Defining Merge
Requires an ordering.
merge Ord a gt a -gt a -gt a merge (x
xs) (y ys) x lt y x merge xs (y ys)
x gt y y merge (x xs) ys merge ys
ys merge xs xs
One list gets smaller.
Two possible base cases.
35The Cost of Sorting
Insertion Sort Sorting n elements takes nn/2
comparisons.
Merge Sort Sorting n elements takes nlog2 n
comparisons.
Num elements Cost by insertion Cost by
merging 10 50 40 1000
500000 10000 1000000
500000000000 20000000
36Recursion Comprehensions
Used together, recursion and list comprehensions
can be a powerful tool. Example Define nub
Eq a gt a -gt a which removes duplicate
elements from a list. E.g. nub 1,2,1,3 1,2,3.
x
y
x
y
...
remove x
y
...
y
nub
y
...
x
37Completing nub
x
y
x
y
...
remove x
y
...
y
nub
y
...
x
nub (x xs) x nub y ylt- xs, y / x nub
38Lessons
Recursion works well on lists we reduce the
problem of computing a function to the same
problem for a shorter list. Often the cases we
consider are f base case f (x xs)
f xs recursive case Sometimes list
comprehensions offer a simpler alternative to
recursion use each one where it is appropriate!
39Reading
This lecture covers roughly the material in
Chapter 7.1-7.5. The book also contains some
excellent exercises, in particular at the end of
section 7.5. Section 7.6 tackles a larger problem
using the methods described in this lecture.