❖ Higher-order Functions |
Recall the quicksort library function
void qsort(void *base, size_t nelems, size_t width, int (*compare)(const void *, const void *));
Sorts an array of items of any type (hence (void *)
base
nelems
width
compare
compare(
)
qsort(myArray, 10, sizeof(char *), strcmp)
❖ ... Higher-order Functions |
qsort()
Note that recursive functions are not necessarily higher-order, but they can be
❖ Pointers to Functions |
C is definitely not a functional language
int (*compare)(const void *, const void *)
compare
(void *)
int
const
❖ ... Pointers to Functions |
How to get a value which is a function pointer ...
qsort
strcmp
&
&qsort
(
strcmp("abc","def")
fgets(buf,10,stdin)
❖ ... Pointers to Functions |
Function pointers ...
//define a function pointer variable "fp" int (*fp)(List); // assign a value to this variable fp = &length; // apply the function being pointed to n = (*fp)(L); // same as n = length(L)
❖ Recursive functions on Lists |
For this discussion, we define List
// a list node contains an integer value typedef struct _node { int val; struct _node *next; } Node; // a List is a pointer to its first Node typedef Node *List; // we also uses Sedgewick's definition typedef Node *Link;
The difference between List
Link
List
Link
❖ ... Recursive functions on Lists |
The following functions help with list manipulation:
// returns a new empty List List new(); // checks whether L is empty bool empty(List L); // returns first element in L int head(List L); // returns all but first element in L List tail(List L); // returns new list with x as head and L as tail List insert(int x, List L); // returns new list with x as last element List append(List L, int x); // returns new list which is concatenation of lists L1 and L2 List concat(List L1, List L2);
❖ Folding Lists |
Example: determining the length of a list
// empty list has length 0 // a non-empty list has at least one element // plus as many as are in the rest of the list int length(List L) { if (empty(L)) return 0; // base case else return 1 + length(tail(L)); }
Exercise: write an iterative version using the empty/head/tail operations
❖ ... Folding Lists |
Example: sum of values in a list
// empty list has sum 0 // a non-empty list has at least one element // plus the sum of the rest of the list int sum(List L) { if (empty(L)) return 0; // base case else return head(L) + sum(tail(L)); }
Note similar structure to length()
❖ ... Folding Lists |
sum()
length()
fold()
int fold(List L, int (*f)(int x, int y), int id)
L
f
int
int
id
f
❖ ... Folding Lists |
The sum
fold
int add(int x, int y) { return x+y; } int sum(List L) { return fold(L, add, 0); }
We could define product
int mult(int x, int y) { return x*y; } int product(List L) { return fold(L, mult, 1); }
❖ ... Folding Lists |
The fold
// compute f(L1, f(L2, f(L3, ... f(Ln,id))))
int fold(List L, int (*f)(int x, int y), int id)
{
if (empty(L))
return id;
else
return f( head(L), fold(tail(L),f,id) );
}
Example: fold([1,2,3],add,0)
add(1,add(2,add(3,0)))
❖ Mapping a List |
Example: print items in a list (one per line)
// print first item, on a line by itself // then print the rest of the items void putList(List L) { if (!empty(L)) { showItem(head(L)); putList(tail(L)); } }
❖ ... Mapping a List |
Example: doubling each item in a list
// apply a function to each item in a list
void doubleUp(List L)
{
if (!empty(L)) {
head(L) = 2 * head(L);
doubleUp(tail(L));
}
}
Notes:
#define head(L) L->val
Node
❖ ... Mapping a List |
printList()
doubleUp()
doubleUp
map()
void map(List L, void (*f)(Link x));
L
f
❖ ... Mapping a List |
Defining doubleUp
map
void timesTwo(Link n) { n->val = n->val * 2; } void doubleUp(List L) { map(L, timesTwo); }
Defining printList
map
void showItem(Link n) { printf("%d\n",n->val); } void printList(List L) { map(L, showItem); }
❖ ... Mapping a List |
The map
void map(List L, void (*f)(Link x)) { if (!empty(L)) { f(L); map(tail(L), f); } }
❖ ... Mapping a List |
A variation on map
List mapp(List L, int (*f)(int x)) { if (empty(L)) return new(); else return insert( f(head(L)), mapp(tail(L),f) ); }
Reminder:
insert(int x, List L)
x
❖ Example: list of fibs |
If we had the following two functions:
// returns a list [1,2,3,...,n] List seq(int n) { ... } // returns n'th fibonacci number int fibonacci(int n) { ... }
Then we could build a list of the first n Fibonacci numbers as
List firstNfib(int n) { return map(seq(n), fibonacci); }
❖ Example: length of a List |
A function that computes the length of a list by
int one(int x) { return 1; } int add(int x, int y) { return x+y; } int length(List L) { return fold(mapp(L,one), add, 0); }
Produced: 7 Aug 2020