Functional Programming PDF
Functional Programming PDF
Tyng–Ruey Chuang
• . . . is prepared for the 2010 Formosan Summer School on Logic, Language, and Com-
putation (FLOLAC) held in Taipei, Taiwan,
http://flolac.iis.sinica.edu.tw/flolac10/
http://creativecommons.org/licenses/by-sa/3.0/
Course outline
Each unit consists of 2 hours of lecture and 1 hour of lab/tutor. Examples will be given
in Objective Caml (O’Caml). Useful online resources about O’Caml:
1
1 Basics of functional programming
1.1 Function, evaluation, and binding
Functions
let x = 1
let y = x + 1
let succ n = n + 1
let z = succ y
• val x : int = 1
val y : int = 2
val succ : int -> int = <fun>
val z : int = 3
let sum x y = x + y
let five = sum 2 3
• val sum : int -> int -> int = <fun>
val five : int = 5
let plus3 = sum 3
let seven = plus3 4
• val plus3 : int -> int = <fun>
val seven : int = 7
Anonymous functions
let succ = fun n -> n + 1
let one = succ 0
let two = (fun n -> n + 1) one
• val succ : int -> int = <fun>
val one : int = 1
val two : int = 2
let sum = fun x -> fun y -> x + y
let plus3 = sum 3
• val sum : int -> int -> int = <fun>
val plus3 : int -> int = <fun>
let twice = fun f -> fun x -> f (f x)
let plus6 = twice plus3
let seven = plus6 one
• val twice : (’a -> ’a) -> ’a -> ’a = <fun>
val plus6 : int -> int = <fun>
val seven : int = 7
2
Functions as arguments and as results
let compose f g = fun x -> f (g x)
let plus3 n = n + 3
let times2 n = n * 2
let this = compose plus3 times2 1
let that = compose times2 plus3 1
• val compose : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
val plus3 : int -> int = <fun>
val times2 : int -> int = <fun>
val this : int = 5
val that : int = 8
Notations in O’Caml
Function application is just juxtaposition, and is left associative. These two definitions
are the same:
• let this = compose plus3 times2 1
• let this = ((compose plus3) times2) 1
Function abstraction is right associative. These two definitions are the same:
• let sum = fun x -> fun y -> x + y
Evaluation in O’Caml
• Expressions are evaluated before they are passed as arguments to the function body.
• The function body is evaluated only when all the arguments are evaluated.
• Functions can be partially applied.
3
Binding in O’Caml
• Lexical binding: Expressions are evaluated and bound to the corresponding identifiers
in the order they appear in the program text.
• Nested binding: Outer bindings are shadowed by inner bindings.
let x = 100
let f y = let x = x + y in x
let x = 10
let z = f x
• Simultaneous binding: Several bindings occur at the same time under the same envi-
ronment.
let x = z
and z = x
• Recursive binding: Identifiers can be referred to when they are being defined.
• Expressiveness: Euclid’s algorithm for greatest common divisor (gcd), assuming inte-
gers m, n > 0:
let u = gcd 57 38
let v = gcd 38 59
4
1.2 Data types
Built-in data types in O’Caml
type unit = ()
type ’a option = None | Some of ’a None, Some 17, Some [None; Some true], . . .
Cartesian product
Function space
5
Expressions, values, and types
• Well-typed expressions:
0, (1 + 2), (sum 2 3), (fun x -> fun y -> x + y), (2, true)
• Ill-typed expressions:
O’Caml is strict
• O’Caml insists on evaluating the arguments in a function application though the ar-
guments may not be required for the computation in the function body. O’Caml is
called a strict language.
• Some functional language, e.g., Haskell, will evaluate the function arguments only
when they are demanded by the computation in the function body. These languages
are non-strict.
• What is wrong in this picture (in O’Caml):
6
Functions to the rescue!
let rec loop x = loop x
7
val init : ’a -> unit -> ’a = <fun>
val read : (unit -> ’a) -> ’a = <fun>
val step : (unit -> int) -> int -> unit -> int = <fun>
val mem : unit -> int = <fun>
val x : unit -> int = <fun>
val y : unit -> int = <fun>
val z : unit -> int = <fun>
val x_y_z : int * int * int = (1, 2, 101)
Programming by pattern-matching
8
• Both have type:
val filter : (’a -> bool) -> ’a list -> ’a list = <fun>
val append : ’a list -> ’a list -> ’a list = <fun>
val this : int list = [2]
val that : int list = [1; 2; 3; 100; 101; 102]
Leaf: ’a tree
Node: ’a * ’a tree * ’a tree -> ’a tree
• In O’Caml, type constructors start with lower-case letters; value constructors start
with upper-case letters.
9
• In O’Caml, type constructors and value constructors are unary. Type construction
uses postfix notation; value construction, prefix.
Some (Node (1, Node (0, Leaf, Leaf), Node (2, Leaf, Leaf)))
has type
10
val build : (’a -> (’b * ’a * ’a) option) -> ’a -> ’b tree = <fun>
val range : int * int -> (int * (int * int) * (int * int)) option = <fun>
val tree1to7 : int tree = Node (4, Node (2, Node (1, Leaf, Leaf), Node (3, Leaf, Leaf)),
Node (6, Node (5, Leaf, Leaf), Node (7, Leaf, Leaf)))
11
Fold function for trees
let rec swap tree =
match tree with
Leaf -> Leaf
| Node (here, left, right) ->
Node (here, swap right, swap left)
12
A new swap function
let swap tree =
let f t = match t with Leaf -> Rec Leaf
| Node (here, left, right) ->
Rec (Node (here, right, left))
in
fold f tree
let tree123 = Rec (Node (2, Rec (Node (1, Rec Leaf, Rec Leaf)),
Rec (Node (1, Rec Leaf, Rec Leaf))))
let tree321 = swap tree123
val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
• Type constructor (α, β) t defines (the only) two forms of a tree node.
• Type constructor α tree defines a tree as a recursive structure via type constructor
(α, β) t. The recursion occurs at the second type argument to t.
• A function of type (α, β) t → β comprises both the base case and the inductive step
necessary for folding a value of type α tree to a value of type β.
13
type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b
type ’a tree = Rec of (’a, ’a tree) t
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>
val build : (’a -> (’b * ’a * ’a) option) -> ’a -> ’b tree = <fun>
val range : int * int -> (int * (int * int) * (int * int)) option = <fun>
val tree1to7 : int tree = Node (4, Node (2, Node (1, Leaf, Leaf), Node (3, Leaf, Leaf)),
Node (6, Node (5, Leaf, Leaf), Node (7, Leaf, Leaf)))
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>
val range : int * int -> (int, int * int) t = <fun>
val balanced : int * int -> int tree = <fun>
val tree1to7 : ...
14
Look at a tree the other way!
type (’a, ’b) t = Leaf | Node of ’a * ’b * ’b
val unfold : (’b -> (’a, ’b) t) -> ’b -> ’a tree = <fun>
• Type constructor (α, β) t defines (the only) two forms of a tree node.
• Type constructor α tree defines a tree as a recursive structure via type constructor
(α, β) t. The recursion occurs at the second type argument to t.
• A function of type β → (α, β) t comprises the co-inductive step necessary for unfolding
a value of type β to a value of type α tree.
15
val map : (’a->’b) * (’c->’d) -> (’a,’c) t -> (’b,’d) t = <fun>
val down : ’a tree -> (’a, ’a tree) t = <fun>
val up : (’a, ’a tree) t -> ’a tree = <fun>
let id x = x
let ($) f g x = f (g x)
val ( $ ) : (’a -> ’b) -> (’c -> ’a) -> ’c -> ’b = <fun>
val fold : ((’a, ’b) t -> ’b) -> ’a tree -> ’b = <fun>
val unfold : (’a -> (’b, ’a) t) -> ’a -> ’b tree = <fun>
val this : ’a tree -> ’a tree = <fun>
val that : ’a tree -> ’a tree = <fun>
16
Functional diagram for fold
In the diagram, functions are arrows, and types are objects.
down -
α tree (α, α tree) t
g
β - (α, β) t
down g
α list - (α, α list) t β - (α, β) t
17
2.2 Parametric Modules
Modules
• A module, also called structure, packs together related definitions (types, values, and
even modules).
module MyStack =
struct
type ’a t = ’a list
let empty = []
let push elm stack = elm :: stack
let pop stack =
match stack with
[] -> None
| head :: tail -> Some (head, tail)
end
Module interfaces
• It acts as a contract between the user and the implementer of a module. Interface
checking is always enforced in O’Caml.
Parametric modules
18
• Type sharing and structure sharing constraints can be used to relate the arguments
and the result.
Tree folding
down -
α tree (α, α tree) t
List folding
19
| Cons (hd, tl) -> Cons (f hd, g tl)
down -
α list (α, α list) t
• Input: a module with a binary type constructor and its map function.
• Output: a module with a unary type constructor, its map function, and its fold and
unfold functions.
20
Mu, the fixed-pointing module
module type MU = functor (B: FUN) -> FIX with module Base = B
Module Tree
module T =
struct
type (’a, ’b) t = Leaf
| Node of ’a * ’b * ’b
Module List
module L =
struct
type (’a, ’b) t = Null
| Cons of ’a * ’b
let map (f, g) t =
match t with Null -> Null
| Cons ( hd, tl) ->
Cons (f hd, g tl)
end
21