CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

References

Referential transparency again

let x = 0 in
let f y = x+y in
(f 1) + (f 1)
let x = 0 in
let f y = x + y in
let z = (f 1) in z+z

These expressions are equivalent in any context. But in ‘not-Ocaml’:

let x = 0 in
let f y = {
  x := x+y ;
  x
} in
(f 1) + (f 1)
let x = 0 in
let f y = {
  x := x+y;
  x
} in
let z = (f 1) in z+z

Assignments can eliminate referential transparency

lies

OCaml has assignment

let x = ref 0 in
let f y =
  let () = x := (!x)+y in !x in
(f 1) + (f 1)

OCaml supports typed references, which refer to memory cells on the heap. The type rules for references are:

e : τ ⇒ ref e : τ ref
e : τ ref ⇒ !e : τ
x : τ ref, e : τ ⇒ x := e : unit

Notice that with references, order of evaluation is important

Ordering evaluations

We can force OCaml to evaluate a sequence of expressions in order using nested lets:

let _ = e1 in
let _ = e2 in (* ... *)
let _ = en in e

OCaml provides a shorthand for this:

e1; e2; (* ... *) en; e

Note 1: ; is a separator, not a terminator.
Note 2: you’ll get a compiler warning if any of e1, e2, …, en does not have type unit.

Ordering evaluations

What about operators and function calls?

let a = ref "A" in
let b = ref "B" in
(a := "C"; !a) ^ (b := !a ^ !b; !b)

In OCaml, this is specified but the programmer must know; the behavior of f(++x,x++); is “implementation specific” in C!

Despite these drawbacks, some things are easiest to compute with assignment.

lazy

Example: “under the hood” of the Lazy module:

type 'a lcell = V of 'a | L of (unit -> 'a)
type 'a t = 'a lcell ref
let force lz = match !lz with
 | L thunk -> let v = thunk () in lz := V v ; v
 | V v -> v
let make_lazy thunk = ref (L thunk)

Memoization

let memo f =
  let ft = ref [] in
  fun x ->
   try List.assoc x ft with
   | Not_found -> let fx = f x in
                   ft := (x,fx)::!ft; fx
let memofib =
  let fibt = ref [] in
  let rec mfib n =
   try List.assoc n !fibt with
   | Not_found -> if n < 2 then n else
     let fn = (mfib (n-1)) + (mfib (n-2)) in
     fibt := (n,fn)::!fibt; fn
  in mfib

Value Restriction

References are a common source of “monomorphic type variables:”

# let r = ref [] ;;
val r : '_weak1 list ref = ...
# r := [1] ;;
- : unit = ()
# r ;;
val r : int list ref = ...

Only immutable values can have polymorphic type in OCaml…

cs2041.org

// reveal.js plugins