expr copy(expr const & a) { switch (a.kind()) { case expr_kind::Var: return mk_var(var_idx(a)); case expr_kind::Constant: return mk_constant(const_name(a)); case expr_kind::Type: return mk_type(ty_level(a)); case expr_kind::Value: return mk_value(static_cast<expr_value*>(a.raw())->m_val); case expr_kind::App: return mk_app(num_args(a), begin_args(a)); case expr_kind::Eq: return mk_eq(eq_lhs(a), eq_rhs(a)); case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a)); case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a)); case expr_kind::MetaVar: return mk_metavar(metavar_idx(a), metavar_ctx(a)); } lean_unreachable(); }
optional<substitution> fo_unify(expr e1, expr e2) { substitution s; unsigned i1, i2; buffer<expr_pair> todo; todo.emplace_back(e1, e2); while (!todo.empty()) { auto p = todo.back(); todo.pop_back(); e1 = find(s, p.first); e2 = find(s, p.second); if (e1 != e2) { if (is_metavar_wo_local_context(e1)) { assign(s, e1, e2); } else if (is_metavar_wo_local_context(e2)) { assign(s, e2, e1); } else if (is_equality(e1) && is_equality(e2)) { expr_pair p1 = get_equality_args(e1); expr_pair p2 = get_equality_args(e2); todo.emplace_back(p1.second, p2.second); todo.emplace_back(p1.first, p2.first); } else { if (e1.kind() != e2.kind()) return optional<substitution>(); switch (e1.kind()) { case expr_kind::Var: case expr_kind::Constant: case expr_kind::Type: case expr_kind::Value: case expr_kind::MetaVar: return optional<substitution>(); case expr_kind::App: i1 = num_args(e1); i2 = num_args(e2); while (i1 > 0 && i2 > 0) { --i1; --i2; if (i1 == 0 && i2 > 0) { todo.emplace_back(arg(e1, i1), mk_app(i2+1, begin_args(e2))); } else if (i2 == 0 && i1 > 0) { todo.emplace_back(mk_app(i1+1, begin_args(e1)), arg(e2, i2)); } else { todo.emplace_back(arg(e1, i1), arg(e2, i2)); } } break; case expr_kind::Lambda: case expr_kind::Pi: todo.emplace_back(abst_body(e1), abst_body(e2)); todo.emplace_back(abst_domain(e1), abst_domain(e2)); break; case expr_kind::Let: todo.emplace_back(let_body(e1), let_body(e2)); todo.emplace_back(let_value(e1), let_value(e2)); if (static_cast<bool>(let_type(e1)) != static_cast<bool>(let_type(e2))) return optional<substitution>(); if (let_type(e1)) { lean_assert(let_type(e2)); todo.emplace_back(*let_type(e1), *let_type(e2)); } break; } } } } return optional<substitution>(s); }