CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

intro Ocaml: functions and recursion

OCaml programs

Expressions

A program is a sequence of expressions that are evaluated one after another.

Last time we saw primitive types, operators, let expressions, and conditionals…

We also saw function applications:

  • let res = fname arg applies function fname : t1 -> t2
  • to argument arg : t1
  • to compute result res : t2

Functions

A function is just another kind of value in OCaml:

  • They can be specified as: fun param-name -> expr

  • e.g. fun x -> x*x

  • let make_exciting = fun s -> s ^ "!"

Applying a function value to an argument binds the parameter name to the argument in the body, so:

  • (fun x -> x+1) 77+18
  • What about make_exciting "learn ocaml" ?

OCaml has syntactic “sugar”: for declaring functions, in particular:

let fname argname = expr is equivalent to let fname = fun argname -> expr, so:

  • let sqr r = r *. r ≡ let sqr = fun r -> r *. r

  • let triple x = 3*x in triple 0let triple = fun x -> 3*x in triple 0

Function types

What happens if we compile (make_exciting 7)?

If f has type τ1 -> τ2 and e has type matching τ1, then the application

(f e) has type matching τ2; otherwise applying f to e is a type error.


Function applications also introduce bindings: In

(fun param -> expr) arg

the scope of the binding from param to arg is the function body, expr.

Recursion

RECURSIVE BINDINGS

Pure functional languages use recursion instead of iteration to express repeated code execution.

e.g. bn = b * bn-1, b0 = 1

let pow2 n =
    if n = 0 then 1
    else 2 * (pow2 (n-1))
in pow2 16

Oops! pow2 is not in scope

OCaml avoids this problem with the rec keyword:

 let rec pow2 n =
     if n = 0 then 1
     else 2 * (pow2 (n-1))
 in pow2 16

Recursive iteration

From earlier classes you have also seen recursive functions like fact : int -> int and fib : int -> int

Define a function starstr : int -> string so that starstr n is a string of n * characters:

let rec starstr n =
  if n <= 0 then "" else
  (starstr (n-1))^"*"

Multiple arguments

val pow2 : int -> int = <fun>
val starbar : int -> string = <fun>

What about multiple parameters, e.g. a*b?

let mul a b = a * b ;;
val mul : int -> int -> int = <fun>

Like let f x = expr is syntactic sugar for let f = fun x -> expr,

The form let f x y = expr is short for

let f = fun x -> (fun y -> expr)

Functions defined this way are called curried functions.

Partial application

OCaml has a language with rules for specifying types:

The operation -> is right-associative so the type

int -> int -> int

is the same type as

int -> (int -> int)

These multi-argument functions “eat their arguments” one at a time, so in

let mul x y = x*y
let f = mul 2

the value f is a result of a “partial application” of mul.

What does it do? What is its type?

Examples

What is the type of…

(fun x y z -> if x then y+z else z)
(fun x y z -> x ^ "," ^ y ^ "," ^ z) "hi"
mul 3.14

What is the result of:

let s = "lol"
let rec repeat_s t = if t = 0 then ""
  else s ^ (repeat_s (t-1))
let s = "zomg"
repeat_s 3

Here’s another way to define a multiple argument function:

let rec pow (b,n) = if n=0 then 1 else b * pow (b,n-1)

val pow : int * int -> int = <fun>


If expression e1 has type τ1 (so e1 : τ1) and e2 : τ2, then

  • The expression (e1, e2) : τ1 * τ2
  • (e1, e2, e3) : τ1 * τ2 * τ3.

These expressions are tuples, an example of structured data in OCaml

(The types of tuples are called product types)

cs2041.org

// reveal.js plugins