feat(library/tactic/rewrite_tactic): add eta-reduction support at esimp

closes #469
This commit is contained in:
Leonardo de Moura 2015-03-12 00:31:10 -07:00
parent a9fa0fead9
commit 7de3d5771d
4 changed files with 87 additions and 24 deletions

View file

@ -10,6 +10,7 @@ Author: Leonardo de Moura
#include "kernel/type_checker.h" #include "kernel/type_checker.h"
#include "kernel/instantiate.h" #include "kernel/instantiate.h"
#include "kernel/abstract.h" #include "kernel/abstract.h"
#include "kernel/free_vars.h"
#include "kernel/inductive/inductive.h" #include "kernel/inductive/inductive.h"
#include "library/reducible.h" #include "library/reducible.h"
#include "library/util.h" #include "library/util.h"
@ -97,6 +98,7 @@ class normalize_fn {
std::function<bool(expr const &)> m_pred; // NOLINT std::function<bool(expr const &)> m_pred; // NOLINT
bool m_save_cnstrs; bool m_save_cnstrs;
constraint_seq m_cnstrs; constraint_seq m_cnstrs;
bool m_use_eta;
expr normalize_binding(expr const & e) { expr normalize_binding(expr const & e) {
expr d = normalize(binding_domain(e)); expr d = normalize(binding_domain(e));
@ -137,6 +139,25 @@ class normalize_fn {
} }
} }
expr try_eta(expr const & e) {
lean_assert(is_lambda(e));
expr const & b = binding_body(e);
if (is_lambda(b)) {
expr new_b = try_eta(b);
if (is_eqp(b, new_b)) {
return e;
} else if (is_app(new_b) && is_var(app_arg(new_b), 0) && !has_free_var(app_fn(new_b), 0)) {
return lower_free_vars(app_fn(new_b), 1);
} else {
return update_binding(e, binding_domain(e), new_b);
}
} else if (is_app(b) && is_var(app_arg(b), 0) && !has_free_var(app_fn(b), 0)) {
return lower_free_vars(app_fn(b), 1);
} else {
return e;
}
}
expr normalize(expr e) { expr normalize(expr e) {
check_system("normalize"); check_system("normalize");
if (!m_pred(e)) if (!m_pred(e))
@ -149,7 +170,14 @@ class normalize_fn {
case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort: case expr_kind::Var: case expr_kind::Constant: case expr_kind::Sort:
case expr_kind::Meta: case expr_kind::Local: case expr_kind::Macro: case expr_kind::Meta: case expr_kind::Local: case expr_kind::Macro:
return e; return e;
case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Lambda: {
e = normalize_binding(e);
if (m_use_eta)
return try_eta(e);
else
return e;
}
case expr_kind::Pi:
return normalize_binding(e); return normalize_binding(e);
case expr_kind::App: case expr_kind::App:
return normalize_app(e); return normalize_app(e);
@ -158,14 +186,14 @@ class normalize_fn {
} }
public: public:
normalize_fn(type_checker & tc, bool save = true): normalize_fn(type_checker & tc, bool save, bool eta):
m_tc(tc), m_ngen(m_tc.mk_ngen()), m_tc(tc), m_ngen(m_tc.mk_ngen()),
m_pred([](expr const &) { return true; }), m_pred([](expr const &) { return true; }),
m_save_cnstrs(save) {} m_save_cnstrs(save), m_use_eta(eta) {}
normalize_fn(type_checker & tc, std::function<bool(expr const &)> const & fn): // NOLINT normalize_fn(type_checker & tc, std::function<bool(expr const &)> const & fn, bool eta): // NOLINT
m_tc(tc), m_ngen(m_tc.mk_ngen()), m_tc(tc), m_ngen(m_tc.mk_ngen()),
m_pred(fn), m_save_cnstrs(true) {} m_pred(fn), m_save_cnstrs(true), m_use_eta(eta) {}
expr operator()(expr const & e) { expr operator()(expr const & e) {
m_cnstrs = constraint_seq(); m_cnstrs = constraint_seq();
@ -182,38 +210,39 @@ public:
constraint_seq get_cnstrs() const { return m_cnstrs; } constraint_seq get_cnstrs() const { return m_cnstrs; }
}; };
expr normalize(environment const & env, expr const & e) { expr normalize(environment const & env, expr const & e, bool eta) {
auto tc = mk_type_checker(env, true); auto tc = mk_type_checker(env, true);
bool save_cnstrs = false; bool save_cnstrs = false;
return normalize_fn(*tc, save_cnstrs)(e); return normalize_fn(*tc, save_cnstrs, eta)(e);
} }
expr normalize(environment const & env, level_param_names const & ls, expr const & e) { expr normalize(environment const & env, level_param_names const & ls, expr const & e, bool eta) {
auto tc = mk_type_checker(env, true); auto tc = mk_type_checker(env, true);
bool save_cnstrs = false; bool save_cnstrs = false;
return normalize_fn(*tc, save_cnstrs)(ls, e); return normalize_fn(*tc, save_cnstrs, eta)(ls, e);
} }
expr normalize(type_checker & tc, expr const & e) { expr normalize(type_checker & tc, expr const & e, bool eta) {
bool save_cnstrs = false; bool save_cnstrs = false;
return normalize_fn(tc, save_cnstrs)(e); return normalize_fn(tc, save_cnstrs, eta)(e);
} }
expr normalize(type_checker & tc, level_param_names const & ls, expr const & e) { expr normalize(type_checker & tc, level_param_names const & ls, expr const & e, bool eta) {
bool save_cnstrs = false; bool save_cnstrs = false;
return normalize_fn(tc, save_cnstrs)(ls, e); return normalize_fn(tc, save_cnstrs, eta)(ls, e);
} }
expr normalize(type_checker & tc, expr const & e, constraint_seq & cs) { expr normalize(type_checker & tc, expr const & e, constraint_seq & cs, bool eta) {
normalize_fn fn(tc); bool save_cnstrs = false;
normalize_fn fn(tc, save_cnstrs, eta);
expr r = fn(e); expr r = fn(e);
cs += fn.get_cnstrs(); cs += fn.get_cnstrs();
return r; return r;
} }
expr normalize(type_checker & tc, expr const & e, std::function<bool(expr const &)> const & pred, // NOLINT expr normalize(type_checker & tc, expr const & e, std::function<bool(expr const &)> const & pred, // NOLINT
constraint_seq & cs) { constraint_seq & cs, bool eta) {
normalize_fn fn(tc, pred); normalize_fn fn(tc, pred, eta);
expr r = fn(e); expr r = fn(e);
cs += fn.get_cnstrs(); cs += fn.get_cnstrs();
return r; return r;

View file

@ -14,23 +14,23 @@ namespace lean {
\remark Unification constraints are only generated if \c e contains meta-variables. \remark Unification constraints are only generated if \c e contains meta-variables.
*/ */
expr normalize(environment const & env, expr const & e); expr normalize(environment const & env, expr const & e, bool eta = false);
expr normalize(environment const & env, level_param_names const & ls, expr const & e); expr normalize(environment const & env, level_param_names const & ls, expr const & e, bool eta = false);
/** \brief Similar to <tt>expr normalize(environment const & env, expr const & e)</tt>, but /** \brief Similar to <tt>expr normalize(environment const & env, expr const & e)</tt>, but
uses the converter associated with \c tc. */ uses the converter associated with \c tc. */
expr normalize(type_checker & tc, expr const & e); expr normalize(type_checker & tc, expr const & e, bool eta = false);
expr normalize(type_checker & tc, level_param_names const & ls, expr const & e); expr normalize(type_checker & tc, level_param_names const & ls, expr const & e, bool eta = false);
/** \brief Return the \c e normal form with respect to \c tc, and store generated constraints /** \brief Return the \c e normal form with respect to \c tc, and store generated constraints
into \c cs. into \c cs.
*/ */
expr normalize(type_checker & tc, expr const & e, constraint_seq & cs); expr normalize(type_checker & tc, expr const & e, constraint_seq & cs, bool eta = false);
/** \brief Return the \c e normal form with respect to \c tc, and store generated constraints /** \brief Return the \c e normal form with respect to \c tc, and store generated constraints
into \c cs. into \c cs.
\remark A sub-expression is evaluated only if \c pred returns true. \remark A sub-expression is evaluated only if \c pred returns true.
*/ */
expr normalize(type_checker & tc, expr const & e, std::function<bool(expr const&)> const & pred, // NOLINT expr normalize(type_checker & tc, expr const & e, std::function<bool(expr const&)> const & pred, // NOLINT
constraint_seq & cs); constraint_seq & cs, bool eta = false);
/** \brief c_unfold hint instructs the normalizer (and simplifier) that /** \brief c_unfold hint instructs the normalizer (and simplifier) that
a function application (f a_1 ... a_i ... a_n) should be unfolded a function application (f a_1 ... a_i ... a_n) should be unfolded

View file

@ -500,7 +500,8 @@ class rewrite_fn {
auto tc = new type_checker(m_env, m_ngen.mk_child(), auto tc = new type_checker(m_env, m_ngen.mk_child(),
std::unique_ptr<converter>(new rewriter_converter(m_env, relax_main_opaque, to_unfold, unfolded))); std::unique_ptr<converter>(new rewriter_converter(m_env, relax_main_opaque, to_unfold, unfolded)));
constraint_seq cs; constraint_seq cs;
expr r = normalize(*tc, e, cs); bool use_eta = true;
expr r = normalize(*tc, e, cs, use_eta);
if (!unfolded || cs) // FAIL if didn't unfolded or generated constraints if (!unfolded || cs) // FAIL if didn't unfolded or generated constraints
return none_expr(); return none_expr();
return some_expr(r); return some_expr(r);

View file

@ -0,0 +1,33 @@
open eq is_equiv funext
constant f : nat → nat → nat
example : (λ x y : nat, f x y) = f :=
rfl
namespace hide
variables {A : Type} {B : A → Type} {C : Πa, B a → Type}
definition homotopy2 [reducible] (f g : Πa b, C a b) : Type :=
Πa b, f a b = g a b
notation f `2`:50 g := homotopy2 f g
definition eq_of_homotopy2 {f g : Πa b, C a b} (H : f 2 g) : f = g :=
eq_of_homotopy (λa, eq_of_homotopy (H a))
definition apD100 {f g : Πa b, C a b} (p : f = g) : f 2 g :=
λa b, apD10 (apD10 p a) b
local attribute eq_of_homotopy [reducible]
definition foo (f g : Πa b, C a b) (H : f 2 g) (a : A)
: apD100 (eq_of_homotopy2 H) a = H a :=
begin
esimp {apD100, eq_of_homotopy2, eq_of_homotopy},
rewrite (retr apD10 (λ(a : A), eq_of_homotopy (H a))),
apply (retr apD10)
end
end hide