fun even x = (print ("even " ^ Int.toString x ^ "\n");
(x = 0) orelse odd (x-1))
and odd x = (print ("odd " ^ Int.toString x ^ "\n");
(x <> 0) andalso even (x-1))
val even = not o odd
(* same as fun even x = not ( odd x ) *)
(* NOTE: this even calls the odd defined above,
which still calls the first even *)
val odd = not o even
(* exceptions are defined similarly to datatypes:
they get a Name, and can carry a payload. All exceptions
are values of type exn. For instance, MaybeANumber : int -> exn *)
exception NotNumber
exception MaybeANumber of int
(* to raise an exception, construct a value of type exn, and just raise it *)
fun even x = if x = 2 then raise NotNumber else raise MaybeANumber(x)
(* to handle exceptions, use the keyword handle, and follow it by what
looks very similar to a case statement. All the handle's branches
must be of the same type, and match the type of the expression above
it *)
val handleEven = fn x =>
even x
handle
NotNumber => false
| MaybeANumber x => x = 3
(* a made-up datatype representing webpages (URL and content) and
their contents (essentially lists of words and links). note the two
datatypes are mutually recursive *)
datatype webtext = Empty
| Link of webpage * string * webtext
| Word of string * webtext
and webpage = Found of string * webtext
| Unfound of string
(* a datatype representing (some) expressions in a language like ML *)
datatype 'a non_empty_list =
One of 'a
| More of 'a * 'a non-empty_list
datatype Expr =
Unit
| Integer of int
| String of string
| Variable of string
| Tuple of Expr non_empty_list
| BinOpExpr of Expr * string * Expr
| FnCall of string * Expr
fun printExpr exp =
case exp of
Unit => print "()"
| Integer i => (print o Int.toString) i
| String s => print ("\"" ^ s ^ "\"")
| Variable v => print v
| BinOpExpr (e1, opr, e2) =>
(printExpr e1; print opr; printExpr e2)
| FnCall (f, e) =>
(print "("; print f; printExpr e; print ")")
| Tuple es => printExprList es
and printExprList es =
let fun printHelp es =
case es of
One e => printExpr e
| More (e, es) => (printExpr e; print ", "; printHelp es)
in
print "(";
printHelp es;
print ")"
end
(* you *could* have written the above in a single function, by
inlining the definition of printExprList into the single call site,
but this shows how the mutual recursion works just fine, and is
clearer to read. *)
type frac = int * int
exception ZeroDenom
datatype result = Pos | Neg | Zero
(* this part is not so interesting, but we use it below *)
fun frac_sign (num,denom) =
if denom=0
then raise ZeroDenom
else if num = 0
then Zero
else if (num > 0 andalso denom > 0) orelse (num < 0 andalso denom < 0)
then Pos
else Neg
(* without mutual recursion *)
fun product_sign_old lst =
let fun inner (lst,curr_res) =
case lst of
[] => curr_res
| hd::tl =>
inner (tl, (* pattern match is the state machine transitions *)
case (curr_res, frac_sign hd) of
(Zero,_) => Zero
| (_,Zero) => Zero
| (Pos,Neg) => Neg
| (Neg,Pos) => Neg
| _ => Pos)
in
inner (lst,Pos)
end
(* with mutual recursion *)
fun product_sign lst =
(* each function describes moves from a particular state *)
let fun gt0 lst =
case lst of
[] => Pos
| hd::tl => case frac_sign hd of
Pos => gt0 tl
| Neg => lt0 tl
| Zero => zero tl
and lt0 lst =
case lst of
[] => Neg
| hd::tl => case frac_sign hd of
Pos => lt0 tl
| Neg => gt0 tl
| Zero => zero tl
and zero lst =
case lst of
[] => Zero
| hd::tl => (* question: why call frac_sign hd? *)
let val _ = frac_sign hd in zero tl end
in
gt0 lst
end