let rec mk_apply sigma r a al =
match a, al with
| App(Fun(Abs), [x]), [y] ->
byValue sigma (subst sigma x y 0)
| _, [b] ->
mk_app (apply r) [a; b]
| _, b :: bl ->
mk_apply sigma r (mk_app (apply r) [a; b]) bl
| _, [] ->
assert false
and eval sigma =
Trace.func "eval" "Eval" Term.pp Term.pp
(fun a ->
match a with
| App(Fun(Apply(r)), [x; y]) ->
let x' = eval sigma x in
(match x' with
| App(Fun(Abs), [z]) ->
eval sigma (subst sigma z (eval sigma y) 0)
| _ ->
let y' = eval sigma y in
if x' == x && y' == y then a else
mk_app (apply(r)) [x'; y'])
| _ ->
a)
and byValue sigma a =
let rec bodies = function
| App(Fun(Abs), [x]) ->
mk_app abs [byValue sigma x]
| App(Fun(Apply(r)), xl) ->
mk_app (apply(r)) (mapl bodies xl)
| a ->
a
in
bodies (eval sigma a)
and hnf sigma a =
match a with
| App(Fun(Abs), [x]) ->
let x' = hnf sigma x in
if x == x' then a else
mk_app abs [x']
| App(Fun(Apply(r)), [x1; x2]) ->
(match hnf sigma x1 with
| App(Fun(Abs), [y]) ->
hnf sigma (subst sigma y x2 0)
| y ->
if y == x1 then a else
mk_app (apply(r)) [y; x2])
| _ ->
a
and byName sigma a =
let rec args a =
match a with
| App(Fun(Abs), [x]) ->
let x' = args x in
if x == x' then a else
mk_app abs [x']
| App(Fun(Apply(r)), x :: xl) ->
let x' = args x
and xl' = mapl (byName sigma) xl in
if x == x' && xl == xl' then a else
mk_app (apply(r)) (x' :: xl')
| _ ->
a
in
args (hnf sigma a)
and subst sigma a s k =
match a with
| Var(x) ->
if Var.is_free x then
let i = Var.d_free x in
if k < i then
Var(Var.mk_free(i - 1))
else if i = k then
s
else
Var(Var.mk_free i)
else
a
| App(Fun(Abs), [x]) ->
mk_abs (subst sigma x (lift s 0) (k + 1))
| App(f, xl) ->
sigma f (substl sigma xl s k)
and substl sigma al s k =
mapl (fun x -> subst sigma x s k) al
and lift a k =
match a with
| Var(x) ->
if Var.is_free x then
let i = Var.d_free x in
if i < k then a else Var(Var.mk_free(i + 1))
else
a
| App(Fun(Abs), [x]) ->
mk_abs (lift x (k + 1))
| App(f, xl) ->
mk_app f (liftl xl k)
and liftl al k =
mapl (fun a -> lift a k) al