Post on 14-Apr-2018
7/30/2019 HigherOrderFunctions
1/50
Lecture 7: Higher-Order Functions
Jean-Noel Monette
Functional Programming 1
September 25, 2012
Based on notes by Pierre Flener, Sven-Olof Nystrom
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 1 / 50
7/30/2019 HigherOrderFunctions
2/50
Today
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 2 / 50
7/30/2019 HigherOrderFunctions
3/50
Introductory Examples
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 3 / 50
7/30/2019 HigherOrderFunctions
4/50
Introductory Examples
Reminder
An anonymous function: a function without a name.
fun double x = 2xval double = fn x => 2x
are equivalent.So are
double 42
(fn x =>
2x) 42
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 4 / 50
I d E l
7/30/2019 HigherOrderFunctions
5/50
Introductory Examples
Insertion Sort on Integers
fun insert x [] = [x]| insert x (y :: ys) =
if x < y
then x : : y : : y selse y :: ( insert x ys );
fun isort [] = []| isort (x :: xs) =
insert x ( isort xs );
How to sort in general (not only integer)?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 5 / 50
I t d t E l
7/30/2019 HigherOrderFunctions
6/50
Introductory Examples
Insertion Sort on any type
fun insert order x [] = [x]| insert order x (y :: ys) =
if order(x,y)then x : : y : : y s
else y :: ( insert order x ys );
fun isort order [] = []| isort order (x :: xs) =
insert order x ( isort order xs );What is the type of the different functions?Exercise (at home): redefine the merge sort to be polymorphic.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 6 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
7/50
Introductory Examples
Example (cont.)
> isort (op isort (op >) [6,3,0,1,7,8,5,9,2,4];val it = [9,8,7,6,5,4,3,2,1,0]: int list> isort String.< [one,two,three,four, five , six ,seven ];
val it = [five ,four,one,seven,six ,three,two]: string list> isort (op int list> isort String.< ;val it = fn: string list > string list> isort (fn (( ,s1 ),( ,s2)) => String.
7/30/2019 HigherOrderFunctions
8/50
Introductory Examples
Higher-order functions
A higher-order function: a function that either
takes functions as arguments or
returns functions as result.Remarks
This is hard to do in an imperative programming language
This is a very powerful mechanism
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 8 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
9/50
Introductory Examples
Reflection on the definition of sum
fun sum [] = 0| sum (x:: l ) = x + sum l;
There are only two places in the function definition that are specific forcomputing a sum:
+, combining data
0, result for empty list
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 9 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
10/50
Introductory Examples
A generalization
Lets define a function reduce so thatreduce + 0 is equal to sum
fun reduce f z [] = z| reduce f z (x:: l) = f(x,reduce f z l );
fun reduce f z = (fn [] => z| (x :: l ) => f(x,reduce f z l ));
Note the similarity between reduce and sum.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 10 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
11/50
y p
Generalization (cont.)
Now, sum can be defined as
fun sum xs = reduce (op +) 0 xs;
val sum = reduce (op +) 0;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 11 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
12/50
y p
Other uses of reduce
What will the following compute?
reduce (op ) 1 [1,2,3,4];
reduce Int .max 0 [1,2,3,44,5,6];
reduce (fn(x,y) => x::y) [] [1,2,3,4];
reduce (fn(x,y) => x::y) [5,6,7] [1,2,3,4];
reduce (fn(x,y) => x::x::y) [] [1,2,3,4];
reduce (op @) [] [[1,2],[34],[5,6,7,89]];
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 12 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
13/50
y
Function composition
A function that takes two functions and returns a function!
fun o (f,g) x = f(g(x));
infix o;
o is predefined. No need to define it.
fun add1 x = x + 1;(add1 o add1) 42;
Exercise: Find values id1 and id2 so that
(id1 o f) x = f x ( for all f , x )
(f o id2) x = f x ( for all f , x )
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 13 / 50
Introductory Examples
7/30/2019 HigherOrderFunctions
14/50
Pair
Another way of building functions:> fun pair (f,g) x = (f x, g x);val pair = fn: ( a > b) (a > c) > a > b c
> pair(add1,add1 o add1);val it = fn: int > int int> it 42;val it = (43,44): int int
>
pair(pair(add1,add1 o add1), add1);val it = fn: int > (int int) int> it 42;val it = ((43,44),43): ( int int) int
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 14 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
15/50
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5
Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 15 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
16/50
Higher-order functions on lists
Several functions are very useful to define operations on lists.
> map;val it = fn: ( a > b) > a list > b list>
foldr;val it = fn: ( a b > b) > b > a list > b> foldl ;val it = fn: ( a b > b) > b > a list > b> List. filter ;
val it = fn: ( a > bool) > a list > a listThose functions are predefined in ML, but we will see the details.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 16 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
17/50
The map function
Apply the same operation on all the elements of a list.( PRE: (none)
POST: [f(a 1), f (a 2 ), ..., f (a n )], if L = [a 1,a 2, ..., a n] )> fun map f [ ] = [ ]
| map f (x :: xs) = f x :: map f xs;val map = fn: (a > b) > a list > b list
> fun square x = xx;val square = fn: int > int>
map square [1,2,3,4];val it = [1,4,9,16]: int list> map (fn(x)=> if x < 3 then 0 else x) [1,2,3,4];val it = [0,0,3,4]: int list
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 17 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
18/50
The map function (cont.)
> map square;val it = fn: int list > int list> map (map square);val it = fn: int list list > int list list> map (map square) [[1,2,34],[5]];val it = [[1,4,1156],[25]]: int list list> map String. bool list
> map String.< [(a,ab), ( hello , bye )];val it = [true , false ]: bool list
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 18 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
19/50
Foldr and foldl
fun foldr f b [] = b| foldr f b (x :: xs) = f(x, foldr f b xs );
fun foldl f b [] = b| foldl f b (x :: xs) = foldl f (f (x, b)) xs;
Do they remind you of any function you have seen before?Which one is tail-recursive?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 19 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
20/50
Examples
Sum the elements of the list.
foldr (op +)0
[0,2,21,4,6];foldl (op +)
0[0,2,21,4,6];
Are they equivalent?Which one would you use? Why?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 20 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
21/50
Examples (cont.)
Check that all elements of a list are even
foldr (fn (x,y) => y andalso x mod 2 = 0)true[0,2,21,4,6];
foldl (fn (x,y) => y andalso x mod 2 = 0)true[0,2,21,4,6];
Are they equivalent?Which one would you use? Why?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 21 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
22/50
Examples (cont.)
Compare
foldr (op ::) [];
foldl (op ::) [];
Are they equivalent?
Which one would you use? Why?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 22 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
23/50
Examples (cont.)
What does this function compute?
fun firstEven (x,NONE) =if x mod 2 = 0 then SOME x else NONE
| firstEven ( , SOME y) = SOME y;
Compare
foldl firstEven NONE;foldr firstEven NONE;
Are they equivalent?
Which one would you use for what?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 23 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
24/50
More examples
Try
foldl (fn(x,n) => n+1) 0
foldr (fn(x,n) => n+1) 0
foldr (fn(x,n) => x) 0
foldl (fn(x,n) => x) 0
fun mystery f = foldr (fn (x,n) => f x :: n) [];
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 24 / 50
Higher-order functions on lists
7/30/2019 HigherOrderFunctions
25/50
Filter
( PRE: (none)POST: the list of elements of the list for which p is true )
fun filter p [] = []| filter p (x :: xs) =
if p x
then
x :: filter p xselse
filter p xs ;
Examples:
filter (fn(x) => x x
7/30/2019 HigherOrderFunctions
26/50
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 26 / 50
More Examples
7/30/2019 HigherOrderFunctions
27/50
Folding over integers
Fold over integers (really natural numbers) gives us a general way torecurse over natural numbers
fun foldint f b 0 = b| foldint f b n = foldint f (f (b,n)) (n1);foldint (op + ) 0 5;foldint (op ) 1 5;foldint (fn ((a,b), ) => (a+b, a)) (1,1) 10;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 27 / 50
More Examples
( )
7/30/2019 HigherOrderFunctions
28/50
Folding over integers (cont.)
fun td a = foldint(fn (b,n) => b andalso (n if td n then n:: l else l )[] n;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 28 / 50
More Examples
7/30/2019 HigherOrderFunctions
29/50
twice and ntimes
We can define a function that tells us how to do something twice:
fun twice f = f o f ;fun add1 x = x+1;
twice add1 56;Or more generally, do something n times:
fun ntimes 0 f x = x| ntimes n f x = ntimes (n1) f (f x);
ntimes 42 twice ;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 29 / 50
Example: Polymorphic Ordered Binary Tree
T bl f C
7/30/2019 HigherOrderFunctions
30/50
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 30 / 50
Example: Polymorphic Ordered Binary Tree
Bi h
7/30/2019 HigherOrderFunctions
31/50
Binary search trees
A Binary search tree is a binary tree which is ordered, i.e.
All values in the left subtree are smaller than the value of the root.All values in the right subtree are larger than the value of the root.
The order can be defined for any type.We will consider the values to be pairs:
The first element is the key.The second is the value that we want to associate with the key.
i.e. we define a dictionary.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 31 / 50
Example: Polymorphic Ordered Binary Tree
Bi h t
7/30/2019 HigherOrderFunctions
32/50
Binary search trees
datatype (a , b) bsTree= Void| Bst of ( a , b) bsTree ( a b) ( a , b) bsTree;
Note:
We want the key to be of some equality type.
The order is not part of the datatype.
It is possible to build a bsTree that is not ordered.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 32 / 50
Example: Polymorphic Ordered Binary Tree
R t i i l t
7/30/2019 HigherOrderFunctions
33/50
Retrieving an element
( PRE: the tree is ordered.POST: if the tree contains the key, return the corresponding
value embedded in SOME. NONE otherwise)
fun retrieve lessThan k Void = NONE| retrieve lessThan key (Bst ( left ,( k, v ), right )) =
if key = k then SOME velse if lessThan (key,k) then retrieve lessThan key leftelse retrieve lessThan key right ;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 33 / 50
Example: Polymorphic Ordered Binary Tree
R t i i g l t ( t )
7/30/2019 HigherOrderFunctions
34/50
Retrieving an element (cont.)
We may use the datatype order instead:
fun retrieve compare k Void = NONE| retrieve compare key (Bst ( left ,( k, v ), right )) =
case compare (key,k)of EQUAL => SOME v| LESS => retrieve compare key left| GREATER => retrieve compare key right;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 34 / 50
Example: Polymorphic Ordered Binary Tree
Inserting an element
7/30/2019 HigherOrderFunctions
35/50
Inserting an element
( PRE: The tree is ordered.POST: If the tree contains the key, a tree with the value replaced .
Otherwise, a tree with the (key, value) pair insertedsuch that the tree is ordered .)
fun insert compare (key,value) Void = Bst(Void,(key, value ),Void)| insert compare (key,value) (Bst ( left ,(k, v ), right )) =
case compare (key,k)of EQUAL => Bst (left,(k,value),right )| LESS => Bst(insert compare (key,value) left , (k,v ), right )
| GREATER => Bst(left,(k,v),insert compare (key,value) right );Exercise: Specify and realise the exists and delete functions. (Delete is abit more difficult.)
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 35 / 50
Example: Polymorphic Ordered Binary Tree
Functional Datatype
7/30/2019 HigherOrderFunctions
36/50
Functional Datatype
Consider again the previous definition of bsTree:
The functional argument compare must be passed at each call
The compare order is not global to the binary search tree
Lets introduce the order in a new datatype:
datatype (a , b) bsTree= Void| Bst of ( a , b) bsTree ( a b) ( a , b) bsTree;
type a ordering = a a > order;
datatype (a, b) obsTree= OrdBsTree of a ordering ( a , b) bsTree;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 36 / 50
Example: Polymorphic Ordered Binary Tree
Inserting an element
7/30/2019 HigherOrderFunctions
37/50
Inserting an element
fun emptyTree compare = OrdBsTree (compare, Void);
fun insert (key, value) OrdBsTree (compare, tree) =let fun insert Void = (key,value)
| insert (Bst ( left ,(k,v ), right )) =case compare (key,k)of EQUAL => Bst (left,(k,value),right)| LESS => Bst(insert left , (k, v ), right )
| GREATER =>
Bst(left,(k,v),insert right )in OrdBstTree (compare, insert tree ) end;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 37 / 50
Higher-Order Functions on Trees
Table of Contents
7/30/2019 HigherOrderFunctions
38/50
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 38 / 50
Higher-Order Functions on Trees
Higher-Order Functions on Trees
7/30/2019 HigherOrderFunctions
39/50
Higher-Order Functions on Trees
Like for lists, it is possible to define generic functions on trees.
mapbt applies some function on all elements of the tree.
Different folding functions can be defined.
We cover here binary trees, but the same might be done for othertypes of trees.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 39 / 50
Higher-Order Functions on Trees
Mapping and reducing a binary tree
7/30/2019 HigherOrderFunctions
40/50
Mapping and reducing a binary tree
datatype (a) btree = Vd | Bt of a a btree a btree;
fun mapbt f Vd = Vd| mapbt f (Bt(v, l , r )) = Bt(f v, mapbt f l , mapbt f r );
fun reducebt f z Vd = z| reducebt f z (Bt(v, l , r )) = f (v,reducebt f z l ,reducebt f z r );
mapbt abs;reducebt (fn ( v , l , r ) => 1 + l + r) 0;
reducebt (fn ( v , l , r ) => 1 + Int.max(l,r)) 0;reducebt (fn ( v , l , r ) => l @ [v] @ r) [];reducebt (fn ( v , l , r ) => Bt(v,r,l)) Vd;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 40 / 50
Higher-Order Functions on Trees
Exercises
7/30/2019 HigherOrderFunctions
41/50
Exercises
Use reducebt to compute if a btree is ordered (according to somegiven order).
Use reducebt to transform a btree into a bsTree.
Define a function map on trees (as in assignment 2).
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 41 / 50
Lazy Evaluation
Table of Contents
7/30/2019 HigherOrderFunctions
42/50
Table of Contents
1 Introductory Examples
2 Higher-order functions on lists
3 More Examples
4 Example: Polymorphic Ordered Binary Tree
5 Higher-Order Functions on Trees
6 Lazy Evaluation
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 42 / 50
Lazy Evaluation
Lazy evaluation
7/30/2019 HigherOrderFunctions
43/50
Lazy evaluation
Idea: Do not evaluate the arguments of a function call before weknow that they will be needed.
Similarly, when computing a datastructure or a list, dont compute
the components before we know that they are needed.In a functional programming language with lazy evaluation, it ismeaningful to write a function that creates (for example) a list of allintegers or a list of all prime numbers. A second function might callthe first and print the first 100.
fun ints n = n :: ints (n+1); does not terminate in SML.
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 43 / 50
Lazy Evaluation
Simulating lazy evaluation
7/30/2019 HigherOrderFunctions
44/50
S g y
In SML (or any other programming language with eager evaluation andhigher-order functions) we can simulate a value computed by lazyevaluation by a function.
Indeed, in the following code, the addition is only perfomed in the secondline:
val lazyFive = (fn () => 3 + 2);val five = lazyFive ();
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 44 / 50
Lazy Evaluation
Example: lazy mult
7/30/2019 HigherOrderFunctions
45/50
p y
fun mult x y =if x = 0 then 0 else x y;
fun lazyMult x y =if x() = 0 then 0 else x() y();
What are the types of the functions?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 45 / 50
Lazy Evaluation
Example: lazy mult
7/30/2019 HigherOrderFunctions
46/50
p y
mult (11) (3 div 0);(fn x => fn y => if x=0 then 0 else xy) (11) (3 div 0);(fn x => fn y => if x=0 then 0 else xy) 0 (3 div 0);(fn y => if 0=0 then 0 else 0y) (3 div 0);(fn y => if 0=0 then 0 else 0y) ( raise Div);raise Div;
lazyMult (fn() => 11) (fn() => 3 div 0);(fn x => fn y => if x()=0 then 0 else x()y()) (fn() => 11) (fn() => 3 div 0);(fn y => if (fn() => 11)()=0 then 0 else (fn() => 11)()y()) (fn() => 3 div 0);if (fn() => 11)()=0 then 0 else (fn() => 11)()(fn() => 3 div 0)();
if 0=0 then 0 else (fn() =>
1
1)()
(fn() =>
3 div 0)();if true then 0 else (fn() => 11)()(fn() => 3 div 0)();0;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 46 / 50
Lazy Evaluation
Simulating infinite sequences
7/30/2019 HigherOrderFunctions
47/50
g q
Infinite sequences can either be represented:
as a function f i = x i where xi is the ith element
or as a pair datatype composed of
the first value, anda function that gives us the next pair.
Question: how would you define basic list operations such as hd, tl, mapfor these representations?
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 47 / 50
Lazy Evaluation
First approach
7/30/2019 HigherOrderFunctions
48/50
fun ints i = i;fun zeroes i = 0;
fun fToList n f =let fun aux m = if m>=n then []
else f m :: aux (m+1);in aux 0 end;
fToList 7 ints ;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 48 / 50
Lazy Evaluation
Second approach
7/30/2019 HigherOrderFunctions
49/50
datatype (a) seq = Pair of a (unit > a seq);
fun ints n = Pair(n,(fn () => ints (n+1)));
fun sToList 0 f = []| sToList n f = let val Pair(v,next) = f()
in v :: sToList (n1) next end;
sToList 7 (fn () => ints 0);
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 49 / 50
Lazy Evaluation
End Note
7/30/2019 HigherOrderFunctions
50/50
A good implementation of a lazy languages must make sure that the valueof a subexpression is never computed more than once. The solutionspresented here do not have that property.
val lazyFive = (fn () => 3 + 2);val six = lazyFive() + 1;val seven = lazyFive() + 2;val height = lazyFive() + 3;
Jean-Noel Monette (UU) Lecture 7: Higher-Order Functions 50 / 50