CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Mutable Data Structures

OCaml has “assignment”

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
# let x = ref "astringref";;
val x : string ref = {contents = "astringref"}
# x := "different";;
- : unit = ()
# !x;;
- : string = "different"

mutable

Wait, what does {contents="astringref"} mean?

OCaml implements references via mutable fields in records:

type 'a myref = { mutable contents : 'a }
let myref v = { contents = v }
let (=:) r v = r.contents <- v
let (!!) r = r.contents
let l1 = ref []
l1 := "newfront"::!l1 ;;
let l2 = myref []
l2 =: "newfront"::!!l2;;

Only fields marked mutable support mutation:

type mixed = { no : bool; mutable maybe : bool }
let r = { no = false; maybe = true};;
r.maybe <- false;; (* OK *)
r.no <- true;; (* type error *)

Note that mutation (<-) has type unit, whereas functional update of records (using with) produces a new value:

type 'a link = { mutable v : 'a; mutable next : 'a link option }
let l1 = { v=7; next = None }
let l2 = { v=0; next = Some l1 }
let l3 = { l2 with next = Some l2 }
let l4 = l3.next <- Some l1

Union find

type 'a union_cell = { v : 'a ;
 mutable p : 'a union_cell option;
 mutable sz : int }

let make_set v = { v = v; p = None; sz=1}
let union s1 s2 = match (s1.p,s2.p) with
| (Some _,_) | (_, Some _) -> invalid_arg "unionfind"
| _ -> let (p,c) = if (s1.sz > s2.sz) then
  (s1,s2) else (s2,s1) in
  p.sz <- p.sz + c.sz ; c.p <- Some p
let rec findp s = match s.p with
| None -> s
| Some p -> let np = findp p in s.p <- Some np ; np

This slide is self-referential

type 'a dlist = Head of 'a * 'a dlist
| Link of 'a * 'a dlist * 'a dlist
| Tail of 'a * 'a dlist
let add_front x dl = match dl with
| Head(y,n) | Link(y,_,n) ->
  let rec new_hd = Head(x,Link(y,new_hd,n))
  in new_hd
| Tail(y,p) ->
  let rec new_hd = Head(x, Tail(y,new_hd))
  in new_hd
let add_tail x dl = match dl with
| Link(w,p,_) | Tail(w,p) -> (* wait, wut? *)

type 'a dlist = Nil | Ln of 'a cell
and 'a cell = {v : 'a ;
               mutable prev : 'a dlist ;
               mutable next : 'a dlist }

let add_tail x dl = match dl with
| Nil -> Ln { v=x ; prev = Nil; next = Nil}
| Ln l ->
  let nutl = Ln {v=x; prev=dl; next=Nil} in
    l.next <- nutl ; nutl

Some data structures with internal references are impossible to construct without assignment (in OCaml):

type 'a pTree = Nil | T of 'a treeNode and
'a treeNode =
{ v : 'a ; up : 'a pTree ;
  left : 'a pTree; right : 'a pTree }
let insert x t = match t with
| T n -> (*code that decides x goes here *)
  let newleaf = T {v=x; up= (* what? *);
                   left = Nil; right = Nil} in
     T {v=n.v; up=n.up; left=newleaf; right=n.right}
type 'a pTree = Nil | T of 'a treeNode
and 'a treeNode =
{ v : 'a ;
  mutable up : 'a pTree ;
  mutable left : 'a pTree;
  mutable right : 'a pTree }
let insert x t = match t with
| T n -> (* ... *)
  let newleaf = T {v=x;up=t;left=Nil;right=Nil}
  in n.left <- newleaf ; t

cs2041.org

// reveal.js plugins