Top Banner
Higher-order functions in OCaml
28

Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Dec 14, 2015

Download

Documents

Mara Brattle
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Higher-order functions in OCaml

Page 2: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Higher-order functions

• A first-order function is one whose parameters and result are all "data"

• A second-order function has one or more first-order functions as parameters or result

• In general, a higher-order function has one or more functions as parameters or result

• OCaml supports higher-order functions

Page 3: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Doubling, revisited

# let rec doubleAll = function [] -> [] | (h::t) -> (2 * h)::(doubleAll t);;val doubleAll : int list -> int list

# doubleAll [1;2;3;4;5];;- : int list = [2; 4; 6; 8; 10]

• This is the usual heavy use of recursion• It's time to simplify things

Page 4: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

map

• map applies a function to every element of a list and returns a list of the results

• map f [x, y, z] returns [f x, f y, f z]• Notice that map takes a function as an

argument

• Ignore for now the fact that map appears to take two arguments!

Page 5: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Doubling list elements with map

# let double x = 2 * x;;val double : int -> int = <fun>

# let doubleAll lst = map double lst;;val doubleAll : int list -> int list = <fun>

# doubleAll [1;2;3;4;5];;- : int list = [2; 4; 6; 8; 10]

• The definition of doubleAll is simpler, but...• ...now we need to expose double to the world

Page 6: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Anonymous functions

• An anonymous function has the form (fun parameter -> body)

• Now we can define doubleAll as let doubleAll lst = map (fun x -> 2*x) lst;;

• This final definition is simple and doesn't require exposing an auxiliary function

Page 7: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

The mysterious map

• ML functions all take a single argument, but...

• map double [1;2;3] works

• map (double, [1;2;3]) gives a type error• Even stranger, (map double) [1;2;3] works!

• # map double;;- : int list -> int list = <fun>

• map double looks like a function...how?

Page 8: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Currying

• In OCaml, functions are values, and there are operations on those values

• Currying absorbs a parameter into a function, creating a new function

• map takes one argument (a function), and returns one result (also a function)

Page 9: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Order of operations

• let add (x, y) = x + y;;– # val add : int * int -> int = <fun>

• But also consider:

• # let add x y = x + y;;– val add : int -> int -> int = <fun>

• add x y is grouped as (add x) y• and int -> int -> int as int -> (int ->

int)

Page 10: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Writing a curried function I

• # let add x y = x + y;;– val add : int -> int -> int = <fun>– That is, add has type int -> (int -> int)– Our new add takes an int argument and produces

an (int -> int) result

• (add 5) 3;; (* currying happens *)

- : int = 8

Page 11: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Writing a curried function II

• let addFive = add 5;;– # val addFive : int -> int = <fun>– Notice this is a val; we are manipulating values

• # addFive 3;; (* use our new function *)– - : int = 8

Page 12: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Defining higher-order functions I

# let apply1 (f, x) = f x;;val apply1 : ('a -> 'b) * 'a -> 'b = <fun>

# apply1 (tl, [1;2;3]);;- : int list = [2; 3]

• But:

• # apply1 tl [1;2;3];;– Characters 7-9:

This expression has type 'a list -> 'a list but is here used with type ('b -> int list -> 'c) * 'b

Page 13: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Defining higher-order functions II

# let apply2 f x = f x;;val apply2 : ('a -> 'b) -> 'a -> 'b = <fun>

# apply2 tl [1;2;3];;- : int list = [2; 3]

# apply2 (tl, [1;2;3]);;Characters 8-19:

This expression has type ('a list -> 'a list) * int list but is here used with type 'b -> 'c

• Advantage: this form can be curried

Page 14: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

A useful function: span

• span finds elements at the front of a list that satisfy a given predicate

• Example:

• span even [2;4;6;7;8;9;10] gives [2, 4; 6]

• span isn't a built-in; we have to write it

Page 15: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Implementing span

# let rec span f lst = if f (hd lst) then (hd lst)::span f (tl lst) else [];;val span : ('a -> bool) -> 'a list -> 'a list

= <fun>

# span even [2;4;6;7;8;9;10];;- : int list = [2; 4; 6]

Page 16: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Extending span: span2

• span returns the elements at the front of a list that satisfy a predicate

• Suppose we extend it to also return the remaining elements

• We can do it with the tools we have, but more tools would be convenient

Page 17: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Generalized assignment

• # let (a, b, c) = (8, 3, 6);;– val a : int = 8

val b : int = 3val c : int = 6

• # let (x::xs) = [1;2;3;4];;– (* Non-exhaustive match warning deleted *)

val x : int = 1val xs : int list = [2; 3; 4]

• Generalized assignment is especially useful when a function returns a tuple

Page 18: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Defining local values with let

• let declaration in expression• let decl1 in let decl2 in expression• # let a = 5 in

let b = 10 in a + b;;

• - : int = 15

• let helps avoid redundant computations

Page 19: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Example of let

# let circleArea radius = let pi = 3.1416 in let square x = x *. x in pi *. square radius;;

val circleArea : float -> float = <fun>

# circleArea 10.0;;

- : float = 314.160000

Page 20: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Implementing span2

# let rec span2 f lst = if f (hd lst) then let (first, second) = span2 f (tl lst) in ((hd lst :: first), second) else ([], lst);; val span2 : ('a -> bool) -> 'a list -> 'a list * 'a

list = <fun>

# span2 even [2;4;6;7;8;9;10];;- : int list * int list = [2; 4; 6], [7; 8; 9; 10]

Page 21: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Another built-in function: partition

• Partition breaks a list into two lists: those elements that satisfy the predicate, and those that don't

• Example:

• # partition even [2;4;6;7;8;9;10];;- : int list * int list = [2; 4; 6; 8; 10], [7; 9]

Page 22: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Quicksort

• Choose the first element as a pivot:– For [3;1;4;1;5;9;2;6;5] choose 3 as the pivot

• Break the list into elements <= pivot, andelements > pivot:– [1; 1; 2] and [4; 5; 9; 6; 5]

• Quicksort the sublists:– [1; 1; 2] and [4; 5; 5; 6; 9]

• Append the sublists with the pivot in the middle:– [1; 1; 2; 3; 4; 5; 5; 6;, 9]

Page 23: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Quicksort in ML

let rec quicksort = function [] -> [] | (x::xs) -> let (front, back) = partition (fun n -> n <= x) xs in (quicksort front) @ (x::(quicksort back));;

val quicksort : 'a list -> 'a list = <fun>

# quicksort [3;1;4;1;5;9;2;6;5;3;6];;- : int list = [1; 1; 2; 3; 3; 4; 5; 5; 6; 6; 9]

Page 24: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Testing if a list is sorted

• The following code tests if a list is sorted:• # let rec sorted = function

[] -> true | [_] -> true | (x::y::rest) -> x <= y && sorted (y::rest);;– val sorted : 'a list -> bool = <fun>

• This applies a (boolean) test to each adjacent pair of elements and "ANDs" the results

• Can we generalize this function?

Page 25: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Generalizing the sorted predicate

• let rec sorted list = match list with [] -> true | [_] -> true | (x::y::rest) -> x <= y && sorted (y::rest);;

• The underlined part is the only part specific to this particular function

• We can replace it with a predicate passed in as a parameter

Page 26: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

pairwise

• let rec pairwise f list = match list with [] -> true | [_] -> true | (x::y::rest) -> (f x y) && pairwise f (y::rest);;

• Here are the changes we have made:– Changed the name from sorted to pairwise– Added the parameter f in two places– changed x <= y to (f x y)

Page 27: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

Using pairwise

# pairwise (<=) [1;3;5;5;9];;- : bool = true

# pairwise (<=) [1;3;5;9;5];;- : bool = false

# pairwise (fun x y -> x = y - 1) [3;4;5;6;7];;- : bool = true

# pairwise (fun x y -> x = y - 1) [3;4;5;7];;- : bool = false

Page 28: Higher-order functions in OCaml. Higher-order functions A first-order function is one whose parameters and result are all "data" A second-order function.

The End