Exception definition exception
of exception Baz; (* no arguments *) exception Foo of string; raise Foo("bar"); Exception handling If a raised exception is not handled, computation always stops. handle here we fear that some exception may be raised in the "handle" section will deal with all exceptions we fear exception OutOfRange of int * int * string; fun safe_comb(n,m) = if n <= 0 then raise OutOfRange(n,m,"") else if m < 0 then raise OutOfRange(n,m,"m must be greater than 0") else if m > n then raise OutOfRange(n,m,"n must be greater than m") else if m=0 orelse m=n then 1 else safe_comb(n-1,m) + safe_comb(n-1,m-1); fun comb(n,m) = safe_comb(n,m) handle OutOfRange(0,0,mess) => 1 | OutOfRange(n,m,mess) => ( print("out of range: n="); print(n); print(" m="); print(m); print("\n"); print(mess); print("\n"); 0 ) ;
MORE EXAMPLES fun expo (x, 1) = x | expo (x:int, y) = x * expo(x, y-1) ; fun inverse x = 1.0 / x handle Div => ( print("divide by zero produces 'infinite' value: "); real(expo(10,10))
Signatures allow tailoring of structures for reuse, for use by multiple persons, etc.
Functors allow abstracting out common code from several related uses.
One more way to hide some elements in a structure: local < definitions > in < more definitions > end Here the definitions after the "local" can be used in those after the "in", but they cannot be seen outside the block. However, all definitions after the "in" are visible outside. "local" block can go anyplace you have a list of definitions (like in a structure). It is simply a fence around some of the definitions in the list. This in not like "let"... in "let" a list of expressions must follow the "in"
structure Foo = struct local exception bad_help ; fun helper x = ... if (oops) raise bad_help ; ; in fun op1 x = ... if (need_help) then helper(k); ... ; fun op2 x = ... ; fun op3 x = ... ; fun op4 x = ... ; end; end;