Lecture 012

Exceptions

Example

Example:

1 div 0 => raise Div
(case [1] of [] => 0) => raise Match
raise Div
raise Fail "I failed"

Types of exception

Types of exception (actually the constructors): because they are value

Div: exn
Match: exn
Fail: string -> exn

Create exceptions

exception Divide
exception Rdivide of real

Divide: exn
Rdivide: real -> exn

Exception as datatype

datatype 'a option = NONE | SOME of 'a
NONE: 'a option
SOME: 'a -> 'a option

Having a type does not mean valuable, so raise Div has no value and has type 'a, raise is not a function but a keyword, that applies after functions. Div is a value.

Polymorphic Exception

Polymorphic Exception

Handel Exception

if e0 loop, exception handle loop if e0 has value, exception handle has original value if e0 raise exception, exception handle assign to new value based on match. if there is no match, keep raise the same exception upward

((e0) handle p1 => e1 | p2 => e2)

Queen

(*threat (int * int) -> (int * int) -> bool *)
fun threat (x, y) (a, b) = x = a
                    orelse y = b
                    orelse x-y=a-b
                    orelse x+y=a+b

(*confict: (int * int) -> (int * int) list -> bool *)
fun conflict p = List.exists (threat p)



USING EXCEPTION

(*addqueens: int * int * (int * int) list -> (int * int) list
REQUIRES: n > 0, 1 <= i <= n. Q non-conflicting
ENSURES: addqueens(n, i, Q) extend Q, else raise Conflict
*)

fun addqueens (i, n, Q)
  = let (*try: int -> (int * int) list*)
      fun try j
        = (if conflict (i, j) Q
           then raise Conflict
           else if i = n
                then (i, j) :: Q
                else addqueens(i+1, n, (i, j) Q)) handel Conflict => if j = n then raise Conflict else try (j+1)
    in
      try 1
    end


(*queens: int -> (int * int) list option *)
fun queens n = (SOME (addqueens (1, n, []))) handle Conflict => NONE



USING CONTINUATION

(*addqueens': int * int * (int * int) list -> ((int * int) list -> 'a) -> (unit -> 'a) -> 'a *)
fun addqueens' (i, n, Q) sk fk
  = let
      fun try j
        = let
            fun fk' () = if j=n then fk() else try (j+1)
          in
            if conflict (i, j) Q then fk' ()
            else if i=n then sk((i, j) : Q)
            else addqueens'(i+1, n, (i, j)::Q) sk fk'
          end
    in
      try 1
    end

(*queens: int -> (int * int) list option *)
fun queen n = addqueens' (1, n, []) SOME (fn () => NONE)


USING NEITHER

fun addqueens'' (i, n, Q)
  = let (*try: int -> (int * int) list option*)
      fun try j
        = (case (if conflict (i, j) Q
                then NONE
                else if i = n
                     then SOME ((i, j) :: Q)
                     else addqueens(i+1, n, (i, j) Q)) of
          NONE => if j = n then NONE else try (j+1)
        | SOME Q' => SOME Q')
    in
      try 1
    end

fun queen n = addqueens'' (i, n, [])

Table of Content