typedef id = string
datatype expr = INT of int
| VAR of id
| LAM of (id, expr)
| APP of (expr, expr)
extern fun print_expr (e: expr): void
overload print with print_expr
implement print_expr (e) = case+ e of
| INT i => printf ("INT(%i)", @(i))
| VAR x => printf ("VAR(%s)", @(x))
| LAM (x, e0) => (print "LAM("; print x; print ", "; print e0; print ")")
| APP (e1, e2) => (print "APP("; print e1; print ", "; print e2; print ")")
fn isval (e: expr): bool = case+ e of
| INT _ => true
| VAR _ => true
| LAM _ => true
| APP _ => false
fn isredex (e: expr): bool = case+ e of
| APP (LAM _, _) => true
| _ => false
datatype evalc = | EChole of ()
| ECapp1 of (evalc, expr)
| ECapp2 of (expr, evalc)
fun compose (E: evalc, e0: expr): expr =
case+ E of
| EChole () => e0
| ECapp1 (evalc, e) => APP (compose (evalc, e0), e)
| ECapp2 (e, evalc) => APP (e, compose (evalc, e0))
fun decompose (e: expr)
: Option @(evalc, expr) =
case+ e of
| INT _ => None ()
| LAM _ => None ()
| VAR _ => None () | APP (e1, e2) => let
val ans = decompose e1
in
case+ ans of
| Some @(E1, r) => Some @(ECapp1 (E1, e2), r)
| None () => let
val ans = decompose e2
in
case+ ans of
| Some @(E2, r) => Some @(ECapp2 (e1, E2), r)
| None () => Some @(EChole, e)
end end
fun subst (e: expr, x: id, v: expr): expr =
case+ e of
| INT _ => e
| VAR x1 => if x = x1 then v else e
| LAM (x1, e0) =>
if x = x1 then e else LAM (x1, subst (e0, x, v))
| APP (e1, e2) => APP (subst (e1, x, v), subst (e2, x, v))
fn eval_redex (e: expr): expr =
case- e of
| APP (LAM (x, e), v) => subst (e, x, v)
extern fun eval (e: expr): expr
implement eval (e) = let
val ans = decompose (e)
in
case+ ans of
| None () => e | Some @(E, r) => let
val c = eval_redex (r)
in
eval (compose (E, c))
end
end
val K = LAM ("x", LAM ("y", VAR "x")) val S = LAM ("x", LAM ("y", LAM ("z", APP (APP (VAR "x", VAR "z"), APP (VAR "y", VAR "z"))))) val SKK = APP (APP (S, K), K)
val () = () where {
val e = APP (SKK, INT 1000)
val () = begin
print "eval("; print e; print ") = "; print (eval e); print_newline ()
end }
implement main () = ()