Download Functional Programming with OCaml: Lecture Notes and Exercises and more Study notes Programming Languages in PDF only on Docsity!
CMSC 330: Organization of
Programming Languages
Functional Programming with OCaml
Review
• Recursion is how all looping is done
• OCaml can easily pass and return functions
Nested Functions
• In OCaml, you can define functions anywhere
– Even inside of other functions
let pick_one n = if n > 0 then (fun x -> x + 1) else (fun x -> x - 1) (pick_one -5) 6 (* returns 5 *)
let sum l = fold ((fun (a, x) -> a + x), 0, l)
Nested Functions (cont’d)
• You can also use let to define functions inside of
other functions
let sum l = let add (a, x) = a + x in fold (add, 0, l)
let pick_one n = let add_one x = x + 1 in let sub_one x = x - 1 in if n > 0 then add_one else sub_one
Consider the Call Stack Again
• How does add know the value of n?
– Read it off the stack?
- (^) Possible, but the semantics are wrong (see above)
– OCaml uses static scoping like C, C++, Java, and Ruby
let addN (n, l) =
map (add, l)
let map (f, n) = match n with [] -> [] | (h::t) -> (f h)::(map (f, t))
addN (3, [1; 2; 3])
let add x = n + x in
n 3
l
f
n
x 1
Static Scoping
• In static or lexical scoping , (nonlocal) names
refer to their nearest binding in the program text
– Going from inner to outer scope
– C example:
– In our example, add accesses addN’s n
int x; void f() { x = 3; } void g() { char *x = "hello"; f(); }
Refers to the x at file scope – that’s
the nearest x going from inner scope
to outer scope in the source code
Environments and Closures
• An environment is a mapping from variable
names to values
– Just like a stack frame
• A closure is a pair (f, e) consisting of function
code f and an environment e
• When you invoke a closure, f is evaluated using
e to look up variable bindings
Example
let add x = (fun y -> x + y)
(add 3) 4 → 4 →^^3 +^4 → 7
Yet Another Example
let twice (n, y) = let f x = x + n in f (f y)
twice (3, 4) → ( 4) → 7 → 10
Still Another Example
let add x = (fun y -> (fun z -> x + y + z))
(((add 1) 2) 3) → (( 2) 3) → ( 3) → 1+2+
Curried Functions in OCaml
• OCaml has a really simple syntax for currying
– This is identical to all of the following:
• Thus:
– add has type int -> (int -> int)
– add 3 has type int -> int
- (^) The return of add x evaluated with x = 3
- (^) add 3 is a function that adds 3 to its argument
- (^) (add 3) 4 = 7
• This works for any number of arguments
let add x y = x + y
let add = (fun x -> (fun y -> x + y)) let add = (fun x y -> x + y) let add x = (fun y -> x+y)
Curried Functions in OCaml (cont’d)
• Because currying is so common, OCaml uses
the following conventions:
– -> associates to the right
- (^) Thus int -> int -> int is the same as
- (^) int -> (int -> int)
– function application associates to the left
- (^) Thus add 3 4 is the same as
- (^) (add 3) 4
Currying and the map Function
• Examples
let negate x = -x
map negate [1; 2; 3] (* returns [-1; -2; -3 ] *)
let negate_list = map negate
negate_list [-1; -2; -3]
let sum_pairs_list = map (fun (a, b) -> a + b)
sum_pairs_list [(1, 2); (3, 4)] (* [3; 7] *)
• What's the type of this form of map?
let rec map f l = match l with [] -> [] | (h::t) -> (f h)::(map f t)
map : ('a -> 'b) -> 'a list -> 'b list
Currying and the fold Function
let rec fold f a l = match l with [] -> a | (h::t) -> fold f (f a h) t
let add x y = x + y
fold add 0 [1; 2; 3]
let sum = fold add 0
sum [1; 2; 3]
let next n _ = n + 1
let length = fold next 0 (* warning: not polymorphic *)
length [4; 5; 6; 7]
• What's the type of this form of fold?
fold : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a