# Lecture 005

## Data Type

### unit

() : unit


### Standard Data Type

#### bool

true : bool
false : bool


### Declaring a Data Type

#### Enumeration Type

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

#### Infinite Type

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


#### Recursive Type

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