Grammar
Expressions
e ::= c (* constants *)
| id (* variables *)
| (fn id => e) (* anonymous functions *)
| e1(e2) (* function applications *)
| u e (* unary operations, ~, not, etc. *)
| e1 b e2 (* binary operations, +,*,etc. *)
| (if e then e1 else e2) (* if expressions *)
| let d in e end (* let expressions *)
Declarations
d ::= val id = e (* value declarations *)
| fun id(id1) = e (* function declarations *)
Values
v ::= c (* constant values *)
| (fn id => e) (* anonymous functions *)
Rule #E1 [constants]
eval(c) = c
Rule #E2 [anonymous functions]
eval(fn id => e) = (fn id => e)
Rule #E3 [function calls]
eval(e1(e2)) = v' where
(0) eval(e1) = (fn id => e)
(1) eval(e2) = v
(2) substitute([(id,v)],e) = e'
(3) eval(e') = v'
Lazy version
eval(e1(e2)) = v' where
(0) eval(e1) = (fn id => e)
(1) substitute([(id,e2)],e) = e'
(2) eval(e') = v'
Rule #E4 [unary operators]
eval(u e) = v where
(0) eval(e) = v'
(1) v = apply_unop(u,v')
Rule #E5 [binary operators]
eval(e1 b e2) = v where
(0) eval(e1) = v1
(1) eval(e2) = v2
(2) v = apply_binop(b,v1,v2)
Rule #E6 [if expressions]
eval(if e then e1 else e2) = v' where
(0) eval(e) = v
(1) if v = true then v' = eval(e1)
(2) if v = false then v' = eval(e2)
Alternate semantics that evaluates both branches
eval(if e then e1 else e2) = v' where
(0) eval(e) = v
(1) eval(e1) = v1
(2) eval(e2) = v2
(3) if v = true then v1
(4) if v = false then v2
Rule #D1[val declarations]
eval_decl(val p = e) = S where
(0) eval(e) = v
(1) create substitution S = [(p, v)]
Rule #E7 [let expressions]
eval(let d in e end) = v where
(0) eval_decl(d) = S
(1) substitute(S,e) = e'
(2) eval(e') = v
Rule #D2[fun declarations]
eval_decl(fun f x = e) = [(f, fun f x = e)]
Rule #E8[fun expressions]
eval(fun f x = e) = (fn x => e') where
substitute([(f, fun f x = e)], e) = e'.