datatype Expr where
| Var(Int)
| Abs(Int, Expr)
| App(Expr, Expr)
end

datatype IntList where
| Cons(Int, IntList)
| Nil
end

function remove(xs: IntList, x: Int) -> IntList
begin
    match xs with
    | Cons(head, tail) =>
        if head == x then
            remove(tail, x)
        else
            Cons(head, remove(tail, x))
    | Nil => Nil
    end
end

function reverse_concat(xs: IntList, ys: IntList) -> IntList
begin
    match ys with
    | Cons(head, tail) => reverse_concat(Cons(head, xs), tail)
    | Nil => xs
    end
end

function free_vars(expr: Expr) -> IntList
begin
    free_vars_help(expr, Nil)
end

function free_vars_help(expr: Expr, acc: IntList) -> IntList
begin
    match expr with
    | Var(x) => Cons(x, acc)
    | Abs(x, e) => remove(free_vars_help(e, acc), x)
    | App(e1, e2) => 
        let vs = free_vars_help(e1, acc);
        free_vars_help(e2, reverse_concat(acc, vs))
    end
end

function gen_lambda_free(expr: Expr)
begin
    guard free_vars(expr) = Nil;
end

query gen_lambda_free(depth_step=5, depth_limit=30)