66
Programming Languages and Techniques (CIS120) Lecture 17 October 12 th , 2015 More Queue ManipulaEon “Objects”

Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Programming  Languages    and  Techniques  

(CIS120)  

Lecture  17  October  12th  ,  2015  

 More  Queue  ManipulaEon  

“Objects”  

Page 2: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Announcements  •  Homework  4:  Queues  

–  Due:  Tomorrow,  October  13th  at  11:59  pm  

•  Homework  5:  GUI  Library  &  Paint  –  Available  Soon  –  Due:  Thursday,  October  22nd    

 

   

Page 3: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

CIS120  

What    happens  when  you  run  this  funcEon  on  a  (valid)  queue  containing  2  elements?    

1. The value 2 is returned2. The value 0 is returned 3. StackOverflow4. Your program hangs

let f (q:'a queue) : int = let rec loop (qn:'a qnode option) : int = begin match qn with | None -> 0 | Some n -> 1 + loop qn end in loop q.head

Page 4: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

CIS120  

What    happens  when  you  run  this  funcEon  on  a  (valid)  queue  containing  2  elements?    

1. The value 2 is returned2. The value 0 is returned 3. StackOverflow4. Your program hangs

let f (q:'a queue) : int = let rec loop (qn:'a qnode option) (len:int) : int = begin match qn with | None -> len | Some n -> loop qn (len + 1) end in loop q.head 0

Page 5: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

More  queue  iteraEon  examples  

to_list  print  

get_tail    

Page 6: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

to_list (using  iteraEon)  

•  Here,  the  state  maintained  across  each  iteraEon  of  the  loop  is  the  queue  “index  pointer”  no  and  the  (reversed)  list  of  elements  traversed.  

•  The  “exit  case”  post  processes  the  list  by  reversing  it.  

    6  

(* Retrieve the list of values stored in the queue, ordered from head to tail. *)let to_list (q: 'a queue) : 'a list = let rec loop (no: 'a qnode option) (l:'a list) : 'a list = begin match no with | None -> List.rev l | Some n -> loop n.next (n.v::l) end in loop q.head []

Page 7: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

print (using  iteraEon)  

•  Here,  the  only  state  needed  is  the  queue  “index  pointer”.  

    7  

let print (q:'a queue) (string_of_element:'a -> string) : unit = let rec loop (no: 'a qnode option) : unit = begin match no with | None -> () | Some n -> print_endline (string_of_element n.v); loop n.next end in print_endline "--- queue contents ---"; loop q.head; print_endline "--- end of queue -----"

Page 8: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Singly-­‐linked  Queue  Processing  •  General  structure    (schemaEcally)  :  

•  What  is  useful  to  put  in  the  state?  –  Accumulated  informaEon  about  the  queue  (e.g.  length  so  far)  –  Link  to  previous  node  (so  that  it  could  be  updated,  for  example)  

   

(* Process a singly-linked queue. *)let queue_operation (q: 'a queue) : ’b = let rec loop (current: 'a qnode option) (s:'a state) : ‘b = begin match no with | None -> … (* iteration complete, produce result *)

| Some n -> … (* do something with n, create new loop state *) loop current.next new_s

end in loop q.head init

Page 9: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

valid  

    9  

(* Determine whether the q satisfies the q invariant *)let valid (q: 'a queue) : bool = begin match (q.head,q.tail) with | (None,None) -> true | (Some n1,Some n2) -> begin match get_tail n1 with | Some n -> n2 == n (* tail is the last node *) | None -> false end | (_,_) -> false end

Either:      (1)    head  and  tail  are  both  None          (i.e.  the  queue  is  empty)  or      (2)  head  is  Some n1,    tail  is Some n2  and                    -­‐        n2  is  reachable  from  n1  by  following  ‘next’  pointers                    -­‐        n2.next  is  None

Page 10: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

get_tail (using  iteraEon)  

•  This  funcEon  works  even  if  the  queue  has  cycles.  –  It  returns  Some  qn  if  qn  is  a  “tail”  reachable  from  hd  (qn  may  be  hd)  –  It  returns  None  if  there  is  a  cycle  

•  The  state  is  an  index  pointer  and  a  list  of  all  the  nodes  seen.  –  contains_alias  is  a  helper  funcEon  that  checks  to  see  whether  n  has  an  

alias  in  the  list  

    10  

(* get the tail (if any) from a queue *)let rec get_tail (hd: 'a qnode) : 'a qnode option = let rec loop (qn: 'a qnode) (seen: 'a qnode list) : 'a qnode option = begin match qn.next with | None -> Some qn | Some n -> if contains_alias n seen then None else loop n (qn::seen) end in loop hd []

Page 11: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

General  Guidelines  •  Processing  must  maintain  the  queue  invariants  •  Update  the  head  and  tail  references  (if  necessary)  •  If  changing  the  link  structure:  

–  SomeEmes  useful  to  keep  reference  to  the  previous  node    (allows  removal  of  the  current  node)  

•  Drawing  pictures  of  the  queue  heap  structure  is  helpful  

•  If  iteraEng  over  the  whole  queue  (e.g.  to  find  an  element)  –  It  is  usually  not  useful  to  use  helpers  like  “is_empty”  or  “contains”  

because  you  will  have  to  account  for  those  cases  during  the  traversal  anyway!  

   

Page 12: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

“Objects”  and  Hidden  State  

EncapsulaEng  State  

Page 13: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

CIS120  

What    number  is  printed  by  this  program?    

1. 12. 23. 34. 45. 56. other

let f = let x = 2 in fun (y : int) -> x + ylet x = 4;; print_int (f 1)

How  did  you  answer  this  quesEon?  1.  SubsEtuEon  model  2.  Abstract  Stack  Machine  3.  I  just  knew  the  answer  4.  I  didn’t  know,  so  I  guessed    

Answer:    3  

Page 14: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

An  “incr”  funcEon  •  FuncEons  with  internal  state  

•  Drawbacks:    –  No  abstrac0on:  There  is  only  one  counter  in  the  world.  If  we  want  

another,  we  need  another  counter_state  value  and  another  incr  funcEon.  

–  No  encapsula0on:    Any  other  code  can  modify  count,  too.  

    16  

type counter_state = { mutable count:int }

let ctr = { count = 0 }

(* each call to incr will produce the next integer *)let incr () : int = ctr.count <- ctr.count + 1; ctr.count

Page 15: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Using  Hidden  State  •  Make  a  funcEon  that  creates  a  counter  state  and  an  incr  

funcEon  each  Eme  a  counter  is  needed.  

    17  

(* More useful: a counter generator: *)let mk_incr () : unit -> int = (* this ctr is private to the returned function *) let ctr = { count = 0 } in fun () -> ctr.count <- ctr.count + 1; ctr.count

(* make one counter *) let incr1 : unit -> int = mk_incr ()

(* make another counter *)let incr2 : unit -> int = mk_incr ()

Page 16: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

CIS120  

What    number  is  printed  by  this  program?    

1. 12. 23. 34. other

Answer:    1  

let mk_incr () : unit -> int = let ctr = { count = 0 } in fun () -> ctr.count <- ctr.count + 1; ctr.count

let incr1 = mk_incr () (* make one counter *) let incr2 = mk_incr () (* and another *)

let _ = incr1 () in print_int (incr2 ())

Page 17: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let mk_incr () : unit -> int = let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

    19  

Page 18: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let mk_incr : unit -> unit -> int = fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

    20  

Page 19: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let mk_incr : unit -> unit -> int = fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

    21  

Page 20: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let mk_incr : unit -> unit -> int = let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

22  

Page 21: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let mk_incr : unit -> unit -> int = . let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

23  

Page 22: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

24  

Page 23: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let incr1 : unit -> int = mk_incr ()

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

25  

Page 24: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let incr1 : unit -> int = ( ())

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

26  

Page 25: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let incr1 : unit -> int = ( ())

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

27  

Page 26: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

28  

Page 27: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

29  

Page 28: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let ctr = in fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0

30  

Page 29: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

let ctr = in fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0

31  

Page 30: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0ctr  

32  

Page 31: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Running  mk_incr    

fun () -> ctr.count <- ctr.count + 1; ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0ctr  

33  

Page 32: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Local  FuncEons  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0ctr  

fun () -> ctr.count <- ctr.count + 1; ctr.count

NOTE:    We  need  one  refinement  of  the  ASM  model  to  handle  local  funcEons.  Why?    The  funcEon  menEons  “ctr”,  which  is  on  the  stack  (but  about  to  be  popped  off)…  

…so  we  save  a  copy  of  the    needed  stack  bindings  with  the  funcEon  itself.    (This  is  someEmes  called  a  closure…)  

ctr  

34  

Page 33: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Local  FuncEons  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

let incr1 : unit -> int = ( )

count 0ctr  

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

POP!  

35  

Page 34: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Local  FuncEons  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

let incr1 : unit -> int = ( )

36  

Page 35: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Local  FuncEons  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

let incr1 : unit -> int = ( )

37  

Page 36: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Local  FuncEons  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr1  

DONE!  Note  how  the  count  record  is  accessible  only  via  the    incr1  funcEon.    This  is  the  sense  in  which  the  state  is  “local”  to  incr1.  

38  

Page 37: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr1 () incr1  

39  

Page 38: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr1 () incr1  

40  

Page 39: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( ()) incr1  

41  

Page 40: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( ()) incr1  

42  

Page 41: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

ctr.count <- ctr.count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

NOTE:  Since  the  funcEon  had  some  saved  stack  bindings,  we  add  them  to  the  stack  at  the  same  Eme  that  we  put  the  code  in  the  workspace.  

43  

Page 42: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

ctr.count <- ctr.count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

44  

Page 43: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- ctr.count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

45  

Page 44: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- ctr.count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

46  

Page 45: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- .count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

47  

Page 46: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- .count + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

48  

Page 47: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- 0 + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

49  

Page 48: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- 0 + 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

50  

Page 49: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

51  

Page 50: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count <- 1;ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

52  

Page 51: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

();ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

53  

Page 52: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

();ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

54  

Page 53: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

55  

Page 54: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

ctr.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

56  

Page 55: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

57  

Page 56: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

.count

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

58  

Page 57: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

1

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

59  

Page 58: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

1

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

( )

incr1  

ctr  

POP!  

60  

Page 59: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  let’s  run  “incr1 ()”  

1

Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr1  

DONE!  

61  

Page 60: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Now  Let’s  run  mk_incr  again  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

let incr2 : unit -> int = mk_incr () incr1  

62  

Page 61: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

…Eme  passes…  

Page 62: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Ajer  creaEng  incr2  Workspace   Stack   Heap  

   

fun () -> let ctr = {count = 0} in fun () -> ctr.count <- ctr.count + 1; ctr.count

mk_incr  

count 1

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr1  

count 0

fun () -> ctr.count <- ctr.count + 1; ctr.count

ctr  

incr2  

NOTE:  the  two  different  incr  funcEons  have  separate  local  states  because  a    new  count  record  was  created  in  each  call  to  mk_incr.  

64  

Page 63: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

One  step  further  •  mk_incr  shows  us  how  to  create  different  instance  of  local  

state  so  that  we  can  have  several  different  counters.  •  What  if  we  want  to  bundle  together  several  operaEons  that  

share  the  same  local  state?  –  e.g.  incr  and  decr  operaEons  that  work  on  the  same  counter  

   

    65  

Page 64: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

A  Counter  Object  

    66  

(* The type of counter objects *)type counter = { get : unit -> int; incr : unit -> unit; decr : unit -> unit; reset : unit -> unit;}

(* Create a fresh counter object with hidden state: *)let new_counter () : counter = let ctr = {count = 0} in { get = (fun () -> ctr.count) ; incr = (fun () -> ctr.count <- ctr.count + 1) ; decr = (fun () -> ctr.count <- ctr.count - 1) ; reset = (fun () -> ctr.count <- 0) ; }

Page 65: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

let c1 = mk_counter ()Stack   Heap  

   

fun () -> let ctr = {count = 0} in { … }

new_counter  

count 1 fun () -> ctr.count

ctr  

67  

fun () -> ctr.count <- ctr.count + 1

ctr  

fun () -> ctr.count <- ctr.count – 1

ctr  

fun () -> ctr.count <- 0

ctr  

get  

incr  

decr  

reset  

c1  

Page 66: Programming)Languages)) and)Techniques) (CIS120))cis120/archive/15fa/lectures/lec17.pdf · valid ))) 9 (* Determine whether the q satisfies the q invariant *) let valid (q: 'a queue)

Using  Counter  Objects  

    68  

(* a helper function to create a nice string for printing *)let ctr_string (s:string) (i:int) = s ^ ".ctr = " ^ (string_of_int i) ^ "\n" let c1 = new_counter ()let c2 = new_counter ()

;; print_string (ctr_string "c1" (c1.get ()));; c1.incr ();; c1.incr ();; print_string (ctr_string "c1" (c1.get ()));; c1.decr ();; print_string (ctr_string "c1" (c1.get ()));; c2.incr ();; print_string (ctr_string "c2" (c2.get ()));; c2.decr ();; print_string (ctr_string "c2" (c2.get ()))