;; open Assert (* Represent maps using lists of pairs. *) (* INVARIANT: there is only one key for each value. *) (* And the keys are stored in order. *) type ('k,'v) map = ('k * 'v) list let empty : ('k,'v) map = [] let is_empty (m:('k,'v) map) = m = [] (* mem takes advantage of the invariant to fail early. *) let rec mem (k:'k) (m:('k,'v) map) : bool = begin match m with | [] -> false | (k2,_) :: t -> k = k2 || (k > k2 && mem k t) end let rec find (k:'k) (m:('k,'v) map) : 'v = begin match m with | [] -> failwith "not found" | (k2,v2) :: t -> if k = k2 then v2 else if k > k2 then find k t else failwith "not found" end let rec remove (k:'k) (m:('k,'v) map) : ('k,'v) map = begin match m with | [] -> [] | (k2,v2) :: t -> if k = k2 then t else if k > k2 then (k2,v2)::remove k t else m end (* replaces if k already in the list *) let rec add (k:'k) (v:'v) (m:('k,'v) map) : ('k,'v) map = begin match m with | [] -> [ (k,v) ] | (k1,v1)::t -> if k < k1 then (k,v) :: (k1,v1) :: t else if k = k1 then (k,v) :: t else (k1,v1) :: add k v t end let rec from_list (l:('k*'v)list) : ('k,'v) map = begin match l with | [] -> empty | (k,v) :: t -> add k v (from_list t) end (* Test cases for map implementation *) type student = string type lab = L201 | L202 | L203 | L204 | L205 | L206 | L207 | L208 type day = Monday | Tuesday | Wednesday | Thursday | Friday | Saturday | Sunday let day_of_lab (l:lab) = begin match l with | L201 | L202 | L203 | L207 -> Wednesday | L204 | L205 | L206 | L208 -> Thursday end (* A type abbreviation for finite maps from students to lab sections. *) type roster = (student*lab) list let roster : (student,lab) map = from_list [ ("Grace", L201); ("Ellis", L201); ("Cory", L202) ; ("Jeremy", L202); ("Rafe", L203) ; ("Harmony", L203); ("Andrew", L204); ("Jessy", L204); ("Nathan", L205); ("Jerry", L205); ("Jason", L206); ("Joseph", L206); ("Boris", L207); ("Xiang", L207); ("Max", L208); ("Nick", L208) ] (* ------ Printing ----------------- *) let string_of_day (d:day) : string = begin match d with | Monday -> "Monday" | Tuesday -> "Tuesday" | Wednesday -> "Wednesday" | Thursday -> "Thursday" | Friday -> "Friday" | Saturday -> "Saturday" | Sunday -> "Sunday" end let string_of_lab (l:lab) = begin match l with | L201 -> "201" | L202 -> "202" | L203 -> "203" | L204 -> "204" | L205 -> "205" | L206 -> "206" | L207 -> "207" | L208 -> "208" end let rec string_of_roster (r : roster) : string = begin match r with | [] -> "" | [ (k,v) ] -> k ^ "->" ^ string_of_lab v | (k,v)::t -> k ^ "->" ^ string_of_lab v ^ "," ^ string_of_roster t end (* ;; print_endline (string_of_roster roster) *) (* ------ Printing ----------------- *) (* ;; print_endline (string_of_roster (add "A" L201 [("B", L201); ("C", L202)])) *) let test () : bool = is_empty empty ;; run_test "is_empty empty" test let test () : bool = not (is_empty roster) ;; run_test "not empty roster" test let test () : bool = mem "Andrew" roster ;; run_test "roster contains Andrew" test let test () : bool = mem "Max" roster ;; run_test "roster contains Max" test let test () : bool = not (mem "Pulak" roster) ;; run_test "roster doesn't contain Pulak" test let test () : bool = find "Rafe" roster = L203 ;; run_test "Rafe is 203" test let test () : bool = find "Joseph" roster = L206 ;; run_test "Joseph is 206" test let test () : bool = not (mem "Nathan" (remove "Nathan" roster)) ;; run_test "remove Nathan" test ;; print_endline "map.ml end of file"