feat(frontends/lean/elaborator): add support for nondependent eliminators in the new elaborator

This commit is contained in:
Leonardo de Moura 2016-09-12 15:26:13 -07:00
parent 9e601cb1cd
commit aa2f9fadee
9 changed files with 63 additions and 24 deletions

View file

@ -6,6 +6,8 @@ Authors: Leonardo de Moura
Basic datatypes
-/
prelude
set_option new_elaborator true
notation `Prop` := Type.{0}
notation `Type₁` := Type.{1}
notation `Type₂` := Type.{2}
@ -36,13 +38,13 @@ structure prod (A B : Type) :=
inductive and (a b : Prop) : Prop
| intro : a → b → and
definition and.elim_left {a b : Prop} (H : and a b) : a :=
and.rec (λa b, a) H
definition and.elim_left {a b : Prop} (H : and a b) : a :=
and.rec (λ Ha Hb, Ha) H
definition and.left := @and.elim_left
definition and.elim_right {a b : Prop} (H : and a b) : b :=
and.rec (λa b, b) H
and.rec (λ Ha Hb, Hb) H
definition and.right := @and.elim_right
@ -362,7 +364,7 @@ namespace eq
subst H₂ H₁
theorem symm : a = b → b = a :=
eq.rec (refl a)
λ h, eq.rec (refl a) h
end eq
notation H1 ▸ H2 := eq.subst H1 H2

View file

@ -216,10 +216,43 @@ bool elaborator::is_elim_elab_candidate(name const & fn) {
return false;
}
/** See comment at elim_info */
auto elaborator::get_elim_info_for_builtin(name const & fn) -> elim_info {
lean_assert(is_aux_recursor(m_env, fn) || inductive::is_elim_rule(m_env, fn));
/* Remark: this is not just an optimization. The code at use_elim_elab_core
only works for dependent elimination. */
lean_assert(!fn.is_atomic());
name const & I_name = fn.get_prefix();
optional<inductive::inductive_decl> decl = inductive::is_inductive_decl(m_env, I_name);
lean_assert(decl);
unsigned nparams = decl->m_num_params;
unsigned nindices = *inductive::get_num_indices(m_env, I_name);
unsigned nminors = length(decl->m_intro_rules);
elim_info r;
if (strcmp(fn.get_string(), "brec_on") == 0 || strcmp(fn.get_string(), "binduction_on") == 0) {
r.m_arity = nparams + 1 /* motive */ + nindices + 1 /* major */ + 1;
} else {
r.m_arity = nparams + 1 /* motive */ + nindices + 1 /* major */ + nminors;
}
r.m_nexplicit = 1 /* major premise */ + nminors;
r.m_motive_idx = nparams;
unsigned major_idx;
if (inductive::is_elim_rule(m_env, fn)) {
major_idx = nparams + 1 + nindices + nminors;
} else {
major_idx = nparams + 1 + nindices;
}
r.m_idxs = to_list(major_idx);
return r;
}
/** See comment at elim_info */
auto elaborator::use_elim_elab_core(name const & fn) -> optional<elim_info> {
if (!is_elim_elab_candidate(fn))
return optional<elim_info>();
if (is_aux_recursor(m_env, fn) || inductive::is_elim_rule(m_env, fn)) {
return optional<elim_info>(get_elim_info_for_builtin(fn));
}
type_context::tmp_locals locals(m_ctx);
declaration d = m_env.get(fn);
expr type = d.get_type();
@ -662,19 +695,19 @@ expr elaborator::visit_elim_app(expr const & fn, elim_info const & info, buffer<
<< " arity: " << info.m_arity << "\n"
<< " nexplicit: " << info.m_nexplicit << "\n"
<< " motive: #" << (info.m_motive_idx+1) << "\n"
<< " major: ";
for (unsigned idx : info.m_explicit_idxs)
<< " \"major\": ";
for (unsigned idx : info.m_idxs)
tout() << " #" << (idx+1);
tout() << "\n";);
expr fn_type = try_to_pi(infer_type(fn));
buffer<expr> new_args;
/* In the first pass we only process the arguments at info.m_explicit_idxs */
/* In the first pass we only process the arguments at info.m_idxs */
expr type = fn_type;
unsigned i = 0;
unsigned j = 0;
list<unsigned> main_idxs = info.m_explicit_idxs;
list<unsigned> main_idxs = info.m_idxs;
buffer<optional<expr>> postponed_args; // mark arguments that must be elaborated in the second pass.
{
while (is_pi(type)) {
@ -749,9 +782,9 @@ expr elaborator::visit_elim_app(expr const & fn, elim_info const & info, buffer<
trace_elab_debug(tout() << "compute motive by using keyed-abstraction:\n " <<
instantiate_mvars(type) << "\nwith\n " <<
expected_type << "\n";);
expr motive = expected_type;
buffer<expr> keys;
get_app_args(type, keys);
expr motive = expected_type;
i = keys.size();
while (i > 0) {
--i;

View file

@ -59,13 +59,14 @@ private:
of the form (C a_1 ... a_n) where C and a_i's are parameters. Moreover, the parameters a_i's
can be inferred using explicit parameters. */
struct elim_info {
unsigned m_arity; /* "arity" of the "eliminator" */
unsigned m_nexplicit; /* Number of explicit arguments */
unsigned m_arity; /* "arity" of the "eliminator" */
unsigned m_nexplicit; /* Number of explicit arguments */
unsigned m_motive_idx; /* Position of the motive (i.e., C) */
list<unsigned> m_explicit_idxs; /* Position of the explicit parameters that we use to synthesize the a_i's */
list<unsigned> m_idxs; // Position of the explicit parameters that we use to synthesize the a_i's
// or need to be processed in the first pass.
elim_info() {}
elim_info(unsigned arity, unsigned nexplicit, unsigned midx, list<unsigned> const & eidxs):
m_arity(arity), m_nexplicit(nexplicit), m_motive_idx(midx), m_explicit_idxs(eidxs) {}
elim_info(unsigned arity, unsigned nexplicit, unsigned midx, list<unsigned> const & idxs):
m_arity(arity), m_nexplicit(nexplicit), m_motive_idx(midx), m_idxs(idxs) {}
};
/** \brief Cache for constants that are handled using "eliminator" elaboration. */
@ -134,6 +135,7 @@ private:
expr enforce_type(expr const & e, expr const & expected_type, char const * header, expr const & ref);
bool is_elim_elab_candidate(name const & fn);
elim_info get_elim_info_for_builtin(name const & fn);
optional<elim_info> use_elim_elab_core(name const & fn);
optional<elim_info> use_elim_elab(name const & fn);

View file

@ -1,2 +1,2 @@
protected definition nat.add : :=
λ a, nat.rec a (λ b₁, nat.succ)
λ a b, nat.rec a (λ b₁ r, nat.succ r) b

View file

@ -2,7 +2,7 @@ map2._main.equations.eqn_2 :
∀ (f : bool → bool → bool) (n : ) (b1 : bool) (v1 : bv n) (b2 : bool) (v2 : bv n),
map2._main f (cons n b1 v1) (cons n b2 v2) = cons n (f b1 b2) (map2._main f v1 v2)
map2'._main.equations.eqn_2 :
∀ (f : bool → bool → bool) (n : ) (b1 : bool) (v1 : bv (nat.rec n (λ (b₁ : ), succ) 0)) (b2 : bool)
(v2 : bv (nat.rec n (λ (b₁ : ), succ) 0)),
map2'._main f (cons (nat.rec n (λ (b₁ : ), succ) 0) b1 v1)
(cons (nat.rec n (λ (b₁ : ), succ) 0) b2 v2) = cons n (f b1 b2) (map2'._main f v1 v2)
∀ (f : bool → bool → bool) (n : ) (b1 : bool) (v1 : bv (nat.rec n (λ (b₁ r : ), succ r) 0)) (b2 : bool)
(v2 : bv (nat.rec n (λ (b₁ r : ), succ r) 0)),
map2'._main f (cons (nat.rec n (λ (b₁ r : ), succ r) 0) b1 v1)
(cons (nat.rec n (λ (b₁ r : ), succ r) 0) b2 v2) = cons n (f b1 b2) (map2'._main f v1 v2)

View file

@ -1,3 +1,5 @@
set_attr1.lean:8:11:failed to generate bytecode for 'ex1'
set_attr1.lean:8:0: warning: proof generation for the prop_simplifier macro has not been implemented yet
set_attr1.lean:15:0: error: tactic failed, result contains meta-variables
state:
n :

View file

@ -1,4 +1,4 @@
succ (nat.rec 2 (λ b₁, succ) 0)
succ (nat.rec 2 (λ b₁ r, succ r) 0)
3
succ (nat.rec a (λ b₁, succ) 0)
succ (nat.rec a (λ b₁ r, succ r) 0)
succ a

View file

@ -1,2 +1,2 @@
?m_1
nat.succ (nat.rec 1 (λ b₁, nat.succ) 0)
nat.succ (nat.rec 1 (λ b₁ r, nat.succ r) 0)

View file

@ -1,4 +1,4 @@
nat.succ (nat.rec a (λ b₁, nat.succ) (nat.rec 1 (λ b₁, nat.succ) 0))
nat.succ (nat.rec a (λ b₁, nat.succ) (nat.rec 1 (λ b₁, nat.succ) 0))
nat.succ (nat.rec a (λ b₁ r, nat.succ r) (nat.rec 1 (λ b₁ r, nat.succ r) 0))
nat.succ (nat.rec a (λ b₁ r, nat.succ r) (nat.rec 1 (λ b₁ r, nat.succ r) 0))
f a
a + 2