170 likes | 270 Views
Remaining Features of SML97. Records Exceptions Reference Types Arrays. Records. type component = { key : int, info : string }; val part = { key = 3, info = “nail” }; (* val part = {info="nail",key=3} : {info:string, key:int} *) #key part = 3;
E N D
Remaining Features of SML97 Records Exceptions Reference Types Arrays L16rem
Records type component = { key : int, info : string }; val part = { key = 3, info = “nail” }; (* val part = {info="nail",key=3} : {info:string, key:int} *) #key part = 3; part = {info = “na” ^ “il”, key = 3-0 }; (* val it = true : bool *) • Order of fields is irrelevant when matching. (2, “two”) = { 1 = 2, 2 = “two” }; • Tuples are special records with numbers as field labels. L16rem
Pattern Matching for Records fun info_compare (p1:component) (p2:component) = String.compare (#info p1, #info p2); fun key_compare ({key=k1,info=_}:component) ({key=k2, ... }:component) = Int.compare (k1, k2); (* Wildcards : Type name mandatory with ellipses. *) fun check_info (c as {key,info}:component) = (#info c = info) ; (* Using a field name to refer to value *) (* maps a component to true *) L16rem
Exceptions • An exception name is a constructor of the built-in type exn. This datatype is special in that the set of constructors can be extended. - exception Overflow; - exception message of string; - exception outOfRange of int*int; - Overflow; (* val it = Overflow(-) : exn *) - message; (* val it = fn : string -> exn *) - outOfRange; (* val it = fn : int * int -> exn *) Predefined exceptions : Div, Empty, Match,... etc. L16rem
Operations on exception raiseexn-name; expressionhandleexn_name1 => … | exn_name2 => … ; Organization CLIENT SERVER Define exception “Trigger” exception Raise exception Handle exception L16rem
Motivation for incorporating exception • Robustness • Language/application specified behavior on error • Context-sensitive handling • Retry • to overcome transient errors • Attempt • another solution strategy (heuristic) on failure • Rescue • reinstate any required invariant (consistency) • Dynamic Handling via run-time call stack L16rem
Examples Server exception fail of string; fun search name [] = raise (fail name) | search name ((x,v)::xvs) = if (name = x) then v else search name xvs; datatype employers = wsu | wpafb | ncr | lexis_nexis ; val name_emp = [(“john”,wsu),(“jane”,ncr)]; (search “jill” name_emp) handle (fail elem) => wpafb; Client L16rem
(cont’d) val name_car = [(“john”, “acura”),(“jane”, “lexus”)]; (search “jill” name_car) handle (fail elem) => elem ^ “ owns Dodge Stealth!”; val name_tel = [(“john”,8501),(“jane”,1359)]; (search “jill” name_tel) handle (fail elem) => elem ^ “’s phone number is unlisted.”; (* type error *) L16rem
References and Assignments L16rem
(ML) Redefinition val x = [5]; val x = 2; (* The first list is inaccessible (garbage). *) • (ML) Shadowing letval x = 5 in (let val x = [2] in (hd x) end) + x end; • (Pascal) Assignment var i: int; begin i := 0; i := i + 1 end; Redefinition and shadowing are different from assignment. L16rem
References • ML supports a separate sub-language to deal with variables and assignments (that can change value bound to a variable). val x = ref 5; x := 6; x := 1 + !x; l-valuer-value (address of location) (contents of location) 5 x L16rem
var i, sum : int := 0; var n : int := 5; while i < n do begin i := i + 1; sum := sum + i end; The l-value of a variable on the rhs of an assignment is automatically coerced to its r-value. val i = ref 0; val sum = ref 0; val n = 5; while !i < n do ( i := !i + 1 ; sum := !sum + !i ); A reference variable on the rhs of an assignment must be explicitly dereferenced, to get its r-value. Iteration : Pascal vs ML L16rem
Aliasing problem fun rot3 (a,b,c) = letval t = !a in a := !b; b := !c; c := t end; val i = ref 0; val j = ref 1; val k = ref 2; (!i,!j,!k); rot3 (i,j,k); (!i,!j,!k); (* (0,1,2) , () : unit, (1,2,0) *) val i = ref 0; val j = ref 1; val k = ref 2; (!i,!j,!i); rot3 (i,j,i); (!i,!j,!i); (* (0,1,0) , () : unit, (0,1,0) *) L16rem
fun new_counter () = let val cnt = ref 0 fun tick () = ( cnt := !cnt + 1; !cnt ) fun reset () = ( cnt := 0 ) in { tick = tick, reset = reset } end; val c1 = new_counter(); val c2 = new_counter(); (#tick c1) (); (* 1 *) (#tick c2) (); (* 1 *) (#tick c1) (); (* 2 *) (#tick c2) (); (* 2 *) (#reset c1) (); (#tick c1) (); (* 1 *) (#tick c2) (); (* 3 *) (* Object-based programming *) Encapsulating State : Objects L16rem
open Array; val n = 3; val M = array(n, array(n,0)); (* Constructs array whose top-level elements share the same inner array. *) val i = ref 0; while (!i < n) do ( update(M,!i,array(n,0)); i := !i + 1 ); (* creates n x n locations initialized to 0 *) i := 0; val j = ref 0; while (!i < n) do ( while (!j < n) do ( update(sub(M,!i),!j,!i + !j); j := !j + 1 ); j := 0; i := !i + 1 ); (* initializesM[i,j]toi+j. *) (* M = [|[|0,1,2|],[|1,2,3|],[|2,3,4|]|] : int array array *) Mutable Data Structure :structure Array L16rem
Interaction with polymorphism • Normally, variables/functions can be polymorphic, but not values. fun id x = x; id 5; ( (fn x => (id x)) 5 ); ( (fn f => (f 5)) id ); (* (fn f => (f 5)) : (int -> 'a) -> 'a *) (id 5, id true); ( (fn f => (f 5, f true)) id ); (* Type error *) L16rem
Polymorphic references are banned. val fp = ref id; (* potential type: ’a->’a ref *) fp := not; !fp 5; Polymorphic exceptions are banned. exception fail of ’a; (raise fail true) handle (fail x) => 0 * x; Value Restriction for polymorphism L16rem