feat(library/init/meta): handle auto_params and opt_params at apply tactic

This commit is contained in:
Leonardo de Moura 2017-06-27 18:17:18 -07:00
parent cdec07fc81
commit e971acabb0
5 changed files with 62 additions and 42 deletions

View file

@ -363,9 +363,10 @@ structure apply_cfg :=
(opt_param := tt)
/-- Apply the expression `e` to the main goal,
the unification is performed using the transparency mode in `cfg`.
If cfg.approx is `tt`, then fallback to first-order unification, and approximate context during unification.
If cfg.all is `tt`, then all unassigned meta-variables are added as new goals.
If cfg.use_instances is `tt`, then use type class resolution to instantiate unassigned meta-variables.
If `cfg.approx` is `tt`, then fallback to first-order unification, and approximate context during unification.
`cfg.new_goals` specifies which unassigned metavariables become new goals, and their order.
If `cfg.instances` is `tt`, then use type class resolution to instantiate unassigned meta-variables.
The fields `cfg.auto_param` and `cfg.opt_param` are ignored by this tactic (See `tactic.apply`).
It returns a list of all introduced meta variables, even the assigned ones. -/
meta constant apply_core (e : expr) (cfg : apply_cfg := {}) : tactic (list expr)
/- Create a fresh meta universe variable. -/
@ -810,14 +811,38 @@ meta def done : tactic unit :=
do n ← num_goals,
when (n ≠ 0) (fail "done tactic failed, there are unsolved goals")
meta def apply (e : expr) : tactic unit :=
apply_core e >> return ()
meta def apply_opt_param : tactic unit :=
do `(opt_param %%t %%v) ← target,
exact v
meta def apply_auto_param : tactic unit :=
do `(auto_param %%type %%tac_name_expr) ← target,
change type,
tac_name ← eval_expr name tac_name_expr,
tac ← eval_expr (tactic unit) (expr.const tac_name []),
tac
meta def has_opt_auto_param (ms : list expr) : tactic bool :=
ms.mfoldl
(λ r m, do type ← infer_type m,
return $ r || type.is_napp_of `opt_param 2 || type.is_napp_of `auto_param 2)
ff
private meta def try_apply_opt_auto_param (cfg : apply_cfg) (ms : list expr) : tactic unit :=
when (cfg.auto_param || cfg.opt_param) $
mwhen (has_opt_auto_param ms) $ do
gs ← get_goals,
ms.mfor' (λ m, set_goals [m] >> try apply_opt_param >> try apply_auto_param),
set_goals gs
meta def apply (e : expr) (cfg : apply_cfg := {}) : tactic unit :=
apply_core e cfg >>= try_apply_opt_auto_param cfg
meta def fapply (e : expr) : tactic unit :=
apply_core e {new_goals := new_goals.all} >> return ()
apply e {new_goals := new_goals.all}
meta def eapply (e : expr) : tactic unit :=
apply_core e {new_goals := new_goals.non_dep_only} >> return ()
apply e {new_goals := new_goals.non_dep_only}
/-- Try to solve the main goal using type class resolution. -/
meta def apply_instance : tactic unit :=
@ -1044,17 +1069,6 @@ updateex_env $ λe, e.add_inductive n ls p ty is is_meta
meta def add_meta_definition (n : name) (lvls : list name) (type value : expr) : tactic unit :=
add_decl (declaration.defn n lvls type value reducibility_hints.abbrev ff)
meta def apply_opt_param : tactic unit :=
do `(opt_param %%t %%v) ← target,
exact v
meta def apply_auto_param : tactic unit :=
do `(auto_param %%type %%tac_name_expr) ← target,
change type,
tac_name ← eval_expr name tac_name_expr,
tac ← eval_expr (tactic unit) (expr.const tac_name []),
tac
meta def rename (curr : name) (new : name) : tactic unit :=
do h ← get_local curr,
n ← revert h,

View file

@ -77,18 +77,6 @@ bool try_instance(type_context & ctx, expr const & meta, tactic_state const & s,
return true;
}
bool try_auto_param(type_context & /* ctx */, expr const & /* meta */,
tactic_state const & /* s */, vm_obj * /* out_error_obj */, char const * /* tac_name */) {
// TODO(Leo)
return true;
}
bool try_opt_param(type_context & /* ctx */, expr const & /* meta */,
tactic_state const & /* s */, vm_obj * /* out_error_obj */, char const * /* tac_name */) {
// TODO(Leo)
return true;
}
/** \brief Given a sequence metas/goals: <tt>(?m_1 ...) (?m_2 ... ) ... (?m_k ...)</tt>,
we say ?m_i is "redundant" if it occurs in the type of some ?m_j.
This procedure removes from metas any redundant element. */
@ -184,17 +172,6 @@ static optional<tactic_state> apply(type_context & ctx, expr e, apply_cfg const
return none_tactic_state();
}
}
/* Synthesize using auto_param and opt_param */
if (cfg.m_opt_param || cfg.m_auto_param) {
unsigned i = metas.size();
while (i > 0) {
--i;
if (cfg.m_opt_param && !try_opt_param(ctx, metas[i], s, out_error_obj, "apply"))
return none_tactic_state();
if (cfg.m_auto_param && !try_auto_param(ctx, metas[i], s, out_error_obj, "apply"))
return none_tactic_state();
}
}
/* Collect unassigned meta-variables */
buffer<expr> new_goals;
for (auto m : metas) {

View file

@ -38,3 +38,31 @@ begin
apply le_refl,
apply le_refl
end
def f (a := 10) : := a + 1
def bla : nat :=
begin
apply f -- uses opt_param for solving goal
end
example : bla = 11 :=
rfl
open tactic
lemma foo {a b c : nat} (h₁ : a = b) (h₂ : b = c . assumption) : a = c :=
eq.trans h₁ h₂
example (a b c : nat) (h₁ : a = b) (h₂ : b = c) : a = c :=
begin
apply foo h₁ -- uses auto_param for solving goal
end
lemma my_div_self (a : nat) (h : a ≠ 0 . assumption) : a / a = 1 :=
sorry
example (a : nat) (h : a ≠ 0) : a / a = 1 :=
begin
apply my_div_self -- uses auto_param for solving goal
end

View file

@ -16,3 +16,4 @@ a :
⊢ ?m_1 = a
a :
⊢ a = a
apply_tac.lean:62:0: warning: declaration 'my_div_self' uses sorry

View file

@ -6,7 +6,7 @@ a + b
def val1 : nat :=
begin
apply @p,
refine @p _ _,
exact 2,
apply_opt_param
end