(* t ::= int | t -> t *) datatype typ = Int | Fun of typ * typ (* use strings to represent variables *) type var = string (* syntactic values; as discussed in class, we include variables * here -- even though the result of an evaluation must be closed * and, therefore, cannot be a variable *) datatype value = Var of var (* x *) | Num of int (* n *) | Lam of var * typ * exp (* \x:t.e *) (* expressions *) and exp = Val of value (* v *) | Suc of exp (* succ(e) *) | Prd of exp (* pred(e) *) | If0 of exp * exp * exp (* if0 e then e else e *) | App of exp * exp (* e e *) (* We represent typing enironment as a (partial) function from * variables to types: *) type env = var -> typ option (* The empty environment is a function that always returns NONE: *) fun empty _ = NONE (* \Gamma[x\mapsto v]: augmenting an environment with an additional * binding: *) fun augment (gamma, x, v) y = if x = y then SOME v else gamma y (* type-check an expression: * This is a partial function from expressions to types. For ill-formed * expressions, we return NONE: * val typecheck: exp -> typ option *) fun typecheck e = let (* split the work between values... *) fun valty (gamma, Var x) = gamma x | valty (_, Num _) = SOME Int | ... (* fill in the remaining case *) | valty (gamma, Lam (x, t, e)) = (* ... and other expressions: *) and expty (gamma, Val v) = valty (gamma, v) | expty (gamma, (Suc e | Prd e)) = ... (* fill this in *) | expty (gamma, If0 (c, t, e)) = ... (* fill this in *) | expty (gamma, App (e1, e2)) = ... (* fill this in *) in (* a well-formed toplevel expression must type-check in an * empty environment: *) expty (empty, e) end (* substitution: * val subst : value * var * exp -> exp *) fun subst (v, x, e) = ... (* fill this in *) (* big-step semantics using substitution: * val bigstep: exp -> value * (Although this function is also partial, we will deal with * failure by raising an exception instead of explicitly returning a * value option.) *) fun bigstep (Val (Var x)) = raise Fail ("unbound variable: " ^ x) | bigstep (Val v) = v | bigstep ... = ... (* fill in the remaining cases *)