(* Lecture 6: Data Structures *) (* Author: Frank Pfenning *) signature QUEUE = sig type 'a queue val empty : 'a queue val enq : 'a queue * 'a -> 'a queue val null : 'a queue -> bool exception Empty (* deq (q) raises Empty if q is empty *) val deq : 'a queue -> 'a * 'a queue end; (* Queue1 gives an inefficient implementation *) (* try also with structure Queue1 : QUEUE to expose the implementation for value printing *) structure Queue1 :> QUEUE = struct type 'a queue = 'a list val empty = nil fun enq (q,x) = q @ [x] fun null (nil) = true | null _ = false exception Empty (* deq (q) raises Empty if q is empty *) fun deq (x::q) = (x,q) | deq (nil) = raise Empty end; (* Queue2 gives a more efficient implementation *) (* try also with structure Queue2 : QUEUE to expose the implementation for value printing *) structure Queue2 :> QUEUE = struct type 'a queue = 'a list * 'a list val empty = (nil,nil) fun enq ((out,inp),x) = (out,x::inp) fun null (nil,nil) = true | null _ = false exception Empty (* deq (q) raises Empty if q is empty *) fun deq (x::out, inp) = (x, (out,inp)) | deq (nil, inp) = (case rev inp of x::out => (x, (out,nil)) | nil => raise Empty) end; (* An abbreviation for the structure name *) (* Try also: structure Q = Queue1 *) structure Q = Queue2; val q0 : int Q.queue = Q.empty; val q1 = Q.enq (q0, 1); val q2 = Q.enq (q1, 2); val q3 = Q.enq (q2, 3); val (x1,q4) = Q.deq (q3); val (x2,q5) = Q.deq (q4); (* Previous queues are still accessible *) val (x1',q4') = Q.deq (q3); (* We can shadow previous queues for garbage collection *) (* Only the last one is accessible, others are shadowed *) val q = Q.empty; val q = Q.enq (q, "a"); val q = Q.enq (q, "b"); val q = Q.enq (q, "c"); val (s1, q) = Q.deq (q); val (s2, q) = Q.deq (q); (* Equality for queues *) (* Elements must permit equality test *) (* val eq : ''a Q.queue * ''a Q.queue -> bool *) (* Inside Queue1 we could write: *) (* fun eq (q1,q2) = (q1 = q2) *) (* Inside Queue2 we could write *) (* fun eq ((out1,inp1), (out2,inp2)) = (out1 @ rev(inp1) = out2 @ rev(inp2)) *) (* Using the abstract types we write *) fun eq (q1, q2) = if Q.null q1 then Q.null q2 else if Q.null q2 then false else let val (x1, q1') = Q.deq q1 val (x2, q2') = Q.deq q2 in x1 = x2 andalso eq(q1,q2) end; (* Using mutual recursion *) (* val eq : ''a Q.queue * ''a Q.queue -> bool *) (* and eq' : (''a * ''a Q.queue) * (''a * ''a Q.queue) -> bool *) fun eq (q1, q2) = if Q.null q1 then Q.null q2 else if Q.null q2 then false else eq' (Q.deq q1, Q.deq q2) and eq' ((x1, q1), (x2, q2)) = x1 = x2 andalso eq (q1, q2); (* Queues of optional integers *) datatype 'a option = NONE | SOME of 'a; type intOptQueue = int option Q.queue; (* Queues of integers or reals *) datatype number = Int of int | Real of real; type numberQueue = number Q.queue;