() : unit
true : bool
false : bool
datatype order = LESS | EQUAL | GREATER
Every datatype is a fresh definition LESS is a constructor that takes 0 argument LESS is a value that can be used as pattern (not all value can be used as pattern)
after declaring, those variables (LESS, EQUAL, GREATER) will be stuck on type order. if we do val LESS = 12
then there is a type error.
so always use all caps, or initial caps to define values of a type
exceptions no caps: true, false, nil
case Int.compare (x, y) of
LESS = ...
| EQUAL = ...
| GREATER = ...
Note that order
is a built-in data type
Int.compare : int * int -> order
String.compare : string * string -> order
datatype extint = NegInfo | Finite of int | PosInf
(* minList int list -> extint *)
fun minList ([]: int list) extint = PosInf
| minList (x :: xs) = (case minList xs of
PosInf => Finite(x)
| Finite (y : int) => Finite(Int.mine(x, y))
| NegInf => ... raise exception
normally this Finite x is a function application, but when Finite is a constructor, Finite 0 is a value, therefore can be used in mapping
so the type extint
type: extint
Finite: int -> extint
PosInf: extint
datatype tree = Empty | Node of tree * int * tree
fun depth (Empty : tree) : int = 0
| depth (Node (left, _, right)) = 1 + Int.max(depth left, depth right)
Theorem: for any value t : tree
, depth T
returns a value (depth is total)
Proof: By structural induction on T
Base Case: T = Empty
WTS: depth Empty returns a value
depth Empty => 0 (1st clause of depth)
Induction Case: T = Node (l, x, r) for some value l, x, r
IH: depth (l) |-> v_l (for some v_l : int) and depth (r) |-> v_r (for some v_r : int)
WTS: depth (Node (l, x, r)) returns to a value
depth (Node (l, x, r))
=> 1 + Int.max(depth l, depth r) (2nd clause)
=> 1 + Int.max(v_l, depth r) (IH:1)
=> 1 + Int.max(v_l, v_r) (IH: 2)
=> some value (by math, since Int.max is total and addition is total)
datatype tree = Leaf of int | Node of tree * tree
(* flatten: tree -> int list *)
fun flatten (Leaf x : tree) : int list = [x]
| flatten (Node (l, r)) = flatten l @ flatten r
Don't use append, that's bad. because we will add each element in the left to right list
(* flatten2: tree -> int list*)
REQUIRES: true
ENSURES: flatten2 (T, acc) = flatten (T) @ acc
fun flatten2 (Leaf x : tree, acc : int list) : int list = x :: acc
| flatten2 (Node (l, r), acc) = flatten (l, flatten2(r, acc))
In this case above, IT IS NOT A TAIL RECURSIVE CALL
flatten2 is not a tail recursive call because it has flatten
to do
flatten is a tail recursive call
so not all functions are tail recursive, therefore, overall non-tail recursive
Table of Content