CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Higher Order Functions:

Generalization, Control Flow, and Polymorphism

Functions as values

Example: many searching tasks, such as

mem : 'a -> 'a list -> bool
find_all : 'a -> 'a list -> 'a list
assoc : 'a -> ('a * 'b) list -> 'b option

Require equality tests. But what makes two elements of type 'a equal?

find : ('a -> bool) -> 'a list -> bool
find_all : ('a -> bool) -> 'a list -> 'a list
assoc_by : ('a -> bool) -> ('a * 'b) list -> 'b option

Lambda expressions, partial applications, and composition can be used to construct function parameters.

Functions as generalization

We can pass functions to generalize the behavior of functions, e.g.

find_all : ('a -> bool) -> 'a list -> 'a list

assoc_by : ('a -> bool) -> ('a*'b) list -> 'b option

let find_range lo hi =

    find_all (fun x -> x > lo && x < hi)

let nearby x y =

   assoc_by (fun (x1,y1) -> ((x -. x1)**2. + (y -. y1)**2.) < 1.)

We can naturally extend this to other examples:

drop_while

drop_until

take_while

What are the types of these functions?

('a -> bool) -> 'a list -> 'a list

Functions as control flow

Java code for hashing a string:

int strhash(String str) {
  int hash = 5381;
  int i = 0;
  while (i < str.length()) {
    hash = hash*33 + str[i];
    i = i+1;
  }
  return hash
}

Notice: the loop has a “store” (hash,i,str), a “body” to update the store, a “test”, and a “return” function of the store:

let hstore = (5381,0,str)
let htest (h,i,str) = i < String.length str
let hbody (h,i,str) =
  let h' = h*33 + (int_of_char str.[i]) in
  let i' = i+1 in (h',i',str)
let hreturn (h,_,_) = h

We can express an arbitrary while loop as:

let loopwhile test body return s =
  let rec loop s =
    if not (test s) then return s
    else loop (body s)
  in loop s

so the hashing loop becomes

let strhash str = loopwhile htest hbody hreturn (5381,0,str)

What is the type of loopwhile?

(test) -> (body) -> (return) -> (store) -> output

('a -> bool) -> ('a -> 'a) -> ('a -> 'b) -> 'a -> 'b

More examples:

int sumup(int n) {
  int s = 0;
  while (n > 0) {
    s = s + f(n);
    n = n-1;
  }
  return s;
}

let sumf f =

int least() {
  int n = 0;
  while (not p(n)) n = n+1;
  return n;
}

let least p =

Functions as polymorphism

So we can pass functions to generalize the behavior of functions, e.g.

find_all : ('a -> bool) -> 'a list -> 'a list

assoc_by : ('a -> bool) -> ('a*'b) list -> 'b option

We can naturally extend this to other examples, e.g., drop_while, drop_until, take_while, …

Ordering operations: listmin, listmax, sort

Data structures with arbitrary element types

Ordering Functions

let listmin ls =
  let rec loop m = function [] -> m
  | h::t -> loop (if h < m then h else m) t
  in match ls with [] -> None | h::t -> Some (loop h t)

let lmin cmp ls =

let lmax cmp ls =

Set operations

Suppose we define a set type as

type 'a set = 'a list

We’ll want functions like mem and empty but also

subset : 'a set -> 'a set -> bool
eq_set : 'a set -> 'a set -> bool
union  : 'a set -> 'a set -> 'a set
intersect : 'a set -> 'a set -> 'a set

What happens if we take the intersection of [ fun x -> x ] and [ fun x -> x ]?

Functions as data values

Functional values can cause polymorphic procedures to fail, e.g.

type 'a btree = Empty | Node of 'a * 'a btree * 'a btree

let rec search t e = match t with
| Empty -> false
| Node (v,lt,rt) -> if e = v then true
  else if e < v then search lt e
  else search rt e

let funtree = Node ((fun x -> x), Empty, Empty)

# search funtree (fun x -> x) ;;

Exception: Invalid_argument "equal: functional value”.

So introduce extra parameter:

type 'a compare = 'a -> 'a -> int
search : 'a compare -> 'a btree -> 'a -> bool

Recall: T is a a binary search tree (bst) iff for each Node(v,lt,rt) in T, every value in lt is less than v and every value in rt is greater than v.

let rec search cmp t e = match t with
| Empty -> false
| Node (v,lt,rt) -> match cmp e v with
  | 0 -> true
  | s when s < 0 -> search cmp lt e
  | _ -> search cmp rt e

Problem: how do we build the binary search tree?

insert: 'a compare-> 'a -> 'a btree -> 'a btree

cs2041.org

// reveal.js plugins