(* Joshua Dunfield *) (* September 2002 *) (* 15-312: Foundations of Programming Languages *) (* Carnegie Mellon University *) (* SML exceptions can leave their scope... *) fun f x = let exception E of string in raise E "doom"; x + 1 end; (f 3) handle E => 0; (* Here's a (not particularly relevant) trick question: E is not in scope, so why does it return 0? *) (* ...and SML exceptions are "generative": *) datatype t = C of exn * (t -> bool) (* exception tester *) fun gen () = let exception G (* Generates a *new* exception, different from all previous, every time gen is applied. *) in C(G, fn C(exc,_) => ((raise exc; (*never gets here*) true) handle G => true | _ => false) ) end; val x = gen(); val y = gen(); fun same (C (_,compare)) other = compare other; same x x; (* true *) same x y; (* false *) (* This really is dynamic -- the compiler is not doing some kind of association of identifiers and exceptions. New exceptions are generated _at runtime_! *) val xs = map gen [(), (), ()]; same (List.nth(xs,0)) (List.nth(xs,0)); (* true *) same (List.nth(xs,2)) (List.nth(xs,2)); (* true *) same (List.nth(xs,1)) (List.nth(xs,2)); (* false *)