type lis = N | C of string * lis

let rec merge l1 l2 = match (l1, l2) with
  N, l2 -> l2
| l1, N -> l1
| (C(i1, t1)), C(i2, t2) ->
    if(i1 < i2) then C(i1, merge t1 l2)
    else if(i1 > i2) then C(i2, merge l1 t2)
    else C(i1, merge t1 t2)

let r1 = merge (N) (N)
let r2 = merge (C("a", C("c", N))) (C("b", N))
let r3 = merge (C("a", C("c", N))) (C("b", C("e", C("h", N))))
let r4 = merge (C("a", C("c", N))) (C("b", C("c", C("h", N))))

(**** Free variables ****)

type tree = Var of string | App of tree * tree

let corec[iterator(N)] fv t = match t with
   Var s -> C(s, N)
| App(t1, t2) -> (merge (fv t1) (fv t2))

let r5 = fv(Var "x")
let r6 = fv(Var "y")
let r7 = fv(App(Var "x", Var "y"))
let r8 = fv(App(Var "x", App(Var "z", Var "y")))

let rec t0 = App(Var "x", App(Var "y", t0))
let r9 = fv(t0)

let r10 = 
  let rec t1 = App(Var "k", App(t0, t1)) in
  t1, fv(t1)

(**** Substitution ****)

let corec[constructor] subst arg = match arg with (* replace variable x by term t *)
      x, t, Var v -> if (v = x) then t else Var v
    | x, t, App(t1, t2) -> App(subst (x, t, t1), subst (x, t, t2))

let r11 = subst ("x", Var "y", Var "y")
let r12 = subst ("x", Var "y", Var "x")
let r13 = subst("x", App(Var "x", Var "x"), App(Var "x", Var "x"))

let rec t0 = App(Var "x", App(Var "y", t0))
let r14 = subst("x", App(Var "z", Var "x"), t0)

let r15 =
  let rec t1 = App(Var "k", App(t0, t1)) in
  subst("x", App(Var "z", Var "x"), t1)
