import("util.lua")
local f, g, a, b, c, d = Consts("f, g, a, b, c, d")
local x = Var(0)
local y = Var(1)
assert(f(a):closed())
local F = f(g(x, a), f(b, f(x, c)))
assert(F:has_free_vars())
assert(F:lift_free_vars(1) == f(g(y, a), f(b, f(y, c))))
print(F)
print(F:instantiate{c, g(b)})
assert(F:instantiate{c, g(b)} == f(g(g(b), a), f(b, f(g(b), c))))
assert(F:instantiate(g(b)) == f(g(g(b), a), f(b, f(g(b), c))))
assert(F:lift_free_vars(1):instantiate{c, g(b)} == f(g(c, a), f(b, f(c, c))))
print(F:lift_free_vars(1):abstract(a))
assert(F:lift_free_vars(1):abstract(a) == f(g(y, x), f(b, f(y, c))))
assert(F:lift_free_vars(1):abstract(a):instantiate{c, d} == f(g(c, d), f(b, f(c, c))))
assert(F:lift_free_vars(1):abstract(a):instantiate{c, d}:abstract{c, b} == f(g(y, d), f(x, f(y, y))))
assert(F:lift_free_vars(1):lower_free_vars(1) == F)
assert(F:lift_free_vars(0, 1):lower_free_vars(1, 1) == F)