chore(library/old_tactic/tactic): remove old tactics that have already been ported to new tactic framework
This commit is contained in:
parent
1590807762
commit
fb836d2d75
34 changed files with 0 additions and 2550 deletions
|
|
@ -1,258 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include <utility>
|
||||
#include "util/lazy_list_fn.h"
|
||||
#include "util/sstream.h"
|
||||
#include "util/name_map.h"
|
||||
#include "util/sexpr/option_declarations.h"
|
||||
#include "kernel/for_each_fn.h"
|
||||
#include "kernel/replace_fn.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "kernel/error_msgs.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/unifier.h"
|
||||
#include "library/util.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/class_instance_resolution.h"
|
||||
#include "library/old_type_checker.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "library/tactic/apply_tactic.h"
|
||||
|
||||
#ifndef LEAN_DEFAULT_APPLY_CLASS_INSTANCE
|
||||
#define LEAN_DEFAULT_APPLY_CLASS_INSTANCE true
|
||||
#endif
|
||||
|
||||
namespace lean {
|
||||
static name * g_apply_class_instance = nullptr;
|
||||
bool get_apply_class_instance(options const & opts) {
|
||||
return opts.get_bool(*g_apply_class_instance, LEAN_DEFAULT_APPLY_CLASS_INSTANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Given a sequence metas: <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.
|
||||
*/
|
||||
static void remove_redundant_metas(buffer<expr> & metas) {
|
||||
buffer<expr> mvars;
|
||||
for (expr const & m : metas)
|
||||
mvars.push_back(get_app_fn(m));
|
||||
unsigned k = 0;
|
||||
for (unsigned i = 0; i < metas.size(); i++) {
|
||||
bool found = false;
|
||||
for (unsigned j = 0; j < metas.size(); j++) {
|
||||
if (j != i) {
|
||||
if (occurs(mvars[i], mlocal_type(mvars[j]))) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
metas[k] = metas[i];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
metas.shrink(k);
|
||||
}
|
||||
|
||||
enum subgoals_action_kind { IgnoreSubgoals, AddRevSubgoals, AddSubgoals, AddAllSubgoals };
|
||||
|
||||
enum add_meta_kind { DoNotAdd, AddDiff, AddAll };
|
||||
|
||||
static proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s,
|
||||
expr const & _e, buffer<constraint> & cs,
|
||||
add_meta_kind add_meta, subgoals_action_kind subgoals_action,
|
||||
optional<unifier_kind> const & uk = optional<unifier_kind>()) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
bool class_inst = get_apply_class_instance(ios.get_options());
|
||||
std::shared_ptr<old_type_checker> tc(mk_type_checker(env));
|
||||
goal g = head(gs);
|
||||
goals tail_gs = tail(gs);
|
||||
expr t = g.get_type();
|
||||
expr e = _e;
|
||||
auto e_t_cs = tc->infer(e);
|
||||
e_t_cs.second.linearize(cs);
|
||||
expr e_t = e_t_cs.first;
|
||||
buffer<expr> metas;
|
||||
old_local_context ctx;
|
||||
bool initialized_ctx = false;
|
||||
unifier_config cfg(ios.get_options());
|
||||
if (uk)
|
||||
cfg.m_kind = *uk;
|
||||
if (add_meta != DoNotAdd) {
|
||||
unsigned num_e_t = get_expect_num_args(tc->get_type_context(), e_t);
|
||||
if (add_meta == AddDiff) {
|
||||
unsigned num_t = get_expect_num_args(tc->get_type_context(), t);
|
||||
if (num_t <= num_e_t)
|
||||
num_e_t -= num_t;
|
||||
else
|
||||
num_e_t = 0;
|
||||
} else {
|
||||
lean_assert(add_meta == AddAll);
|
||||
}
|
||||
for (unsigned i = 0; i < num_e_t; i++) {
|
||||
auto e_t_cs = tc->whnf(e_t);
|
||||
e_t_cs.second.linearize(cs);
|
||||
e_t = e_t_cs.first;
|
||||
expr meta;
|
||||
if (class_inst && binding_info(e_t).is_inst_implicit()) {
|
||||
if (!initialized_ctx) {
|
||||
ctx = g.to_local_context();
|
||||
initialized_ctx = true;
|
||||
}
|
||||
bool use_local_insts = true;
|
||||
bool is_strict = false;
|
||||
auto mc = mk_class_instance_elaborator(
|
||||
env, ios, ctx, optional<name>(),
|
||||
use_local_insts, is_strict,
|
||||
some_expr(head_beta_reduce(binding_domain(e_t))), e.get_tag(), nullptr);
|
||||
meta = mc.first;
|
||||
cs.push_back(mc.second);
|
||||
} else {
|
||||
meta = g.mk_meta(mk_fresh_name(), head_beta_reduce(binding_domain(e_t)));
|
||||
}
|
||||
e = mk_app(e, meta);
|
||||
e_t = instantiate(binding_body(e_t), meta);
|
||||
metas.push_back(meta);
|
||||
}
|
||||
}
|
||||
pair<bool, constraint_seq> dcs = tc->is_def_eq(t, e_t);
|
||||
if (!dcs.first) {
|
||||
throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) {
|
||||
format r = format("invalid 'apply' tactic, failed to unify");
|
||||
r += pp_indent_expr(fmt, t);
|
||||
r += compose(line(), format("with"));
|
||||
r += pp_indent_expr(fmt, e_t);
|
||||
return r;
|
||||
});
|
||||
return proof_state_seq();
|
||||
}
|
||||
dcs.second.linearize(cs);
|
||||
unify_result_seq rseq = unify(env, cs.size(), cs.data(), s.get_subst(), cfg);
|
||||
list<expr> meta_lst = to_list(metas.begin(), metas.end());
|
||||
return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state {
|
||||
substitution const & subst = p.first;
|
||||
constraints const & postponed = p.second;
|
||||
substitution new_subst = subst;
|
||||
expr new_e = new_subst.instantiate_all(e);
|
||||
assign(new_subst, g, new_e);
|
||||
goals new_gs = tail_gs;
|
||||
if (subgoals_action != IgnoreSubgoals) {
|
||||
buffer<expr> metas;
|
||||
for (auto m : meta_lst) {
|
||||
if (!new_subst.is_assigned(get_app_fn(m)))
|
||||
metas.push_back(m);
|
||||
}
|
||||
if (subgoals_action == AddRevSubgoals) {
|
||||
for (unsigned i = 0; i < metas.size(); i++)
|
||||
new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
|
||||
} else {
|
||||
lean_assert(subgoals_action == AddSubgoals || subgoals_action == AddAllSubgoals);
|
||||
if (subgoals_action == AddSubgoals)
|
||||
remove_redundant_metas(metas);
|
||||
unsigned i = metas.size();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
new_gs = cons(goal(metas[i], new_subst.instantiate_all(tc->infer(metas[i]).first)), new_gs);
|
||||
}
|
||||
}
|
||||
}
|
||||
return proof_state(s, new_gs, new_subst, postponed);
|
||||
});
|
||||
}
|
||||
|
||||
proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & e, constraint_seq const & cs) {
|
||||
buffer<constraint> tmp_cs;
|
||||
cs.linearize(tmp_cs);
|
||||
return apply_tactic_core(env, ios, s, e, tmp_cs, AddDiff, AddSubgoals);
|
||||
}
|
||||
|
||||
proof_state_seq fapply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & e, constraint_seq const & cs) {
|
||||
buffer<constraint> tmp_cs;
|
||||
cs.linearize(tmp_cs);
|
||||
return apply_tactic_core(env, ios, s, e, tmp_cs, AddDiff, AddAllSubgoals);
|
||||
}
|
||||
|
||||
tactic apply_tactic_core(expr const & e, constraint_seq const & cs) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
return apply_tactic_core(env, ios, s, e, cs);
|
||||
});
|
||||
}
|
||||
|
||||
tactic apply_tactic_core(elaborate_fn const & elab, expr const & e, add_meta_kind add_meta, subgoals_action_kind k) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
expr new_e; substitution new_subst; constraints cs_;
|
||||
try {
|
||||
auto ecs = elab(g, ios.get_options(), e, none_expr(), s.get_subst(), false);
|
||||
std::tie(new_e, new_subst, cs_) = ecs;
|
||||
buffer<constraint> cs;
|
||||
to_buffer(cs_, cs);
|
||||
to_buffer(s.get_postponed(), cs);
|
||||
proof_state new_s(s, new_subst, constraints());
|
||||
return apply_tactic_core(env, ios, new_s, new_e, cs, add_meta, k);
|
||||
} catch (exception &) {
|
||||
if (s.report_failure())
|
||||
throw;
|
||||
else
|
||||
return proof_state_seq();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tactic apply_tactic(elaborate_fn const & elab, expr const & e) {
|
||||
return apply_tactic_core(elab, e, AddDiff, AddSubgoals);
|
||||
}
|
||||
|
||||
tactic fapply_tactic(elaborate_fn const & elab, expr const & e) {
|
||||
return apply_tactic_core(elab, e, AddDiff, AddAllSubgoals);
|
||||
}
|
||||
|
||||
tactic eapply_tactic(elaborate_fn const & elab, expr const & e) {
|
||||
return apply_tactic_core(elab, e, AddAll, AddSubgoals);
|
||||
}
|
||||
|
||||
void initialize_apply_tactic() {
|
||||
g_apply_class_instance = new name{"apply", "class_instance"};
|
||||
register_bool_option(*g_apply_class_instance, LEAN_DEFAULT_APPLY_CLASS_INSTANCE,
|
||||
"(apply tactic) if true apply tactic uses class-instances "
|
||||
"resolution for instance implicit arguments");
|
||||
|
||||
register_tac(get_tactic_apply_name(),
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'apply' tactic, invalid argument");
|
||||
return apply_tactic(fn, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
|
||||
register_tac(get_tactic_eapply_name(),
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'eapply' tactic, invalid argument");
|
||||
return eapply_tactic(fn, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
|
||||
register_tac(get_tactic_fapply_name(),
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'fapply' tactic, invalid argument");
|
||||
return fapply_tactic(fn, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_apply_tactic() {
|
||||
delete g_apply_class_instance;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/elaborate.h"
|
||||
namespace lean {
|
||||
proof_state_seq apply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & e, constraint_seq const & cs);
|
||||
proof_state_seq fapply_tactic_core(environment const & env, io_state const & ios, proof_state const & s, expr const & e, constraint_seq const & cs);
|
||||
tactic apply_tactic_core(expr const & e, constraint_seq const & cs = constraint_seq());
|
||||
tactic apply_tactic(elaborate_fn const & fn, expr const & e);
|
||||
tactic fapply_tactic(elaborate_fn const & fn, expr const & e);
|
||||
tactic eassumption_tactic();
|
||||
tactic assumption_tactic();
|
||||
void initialize_apply_tactic();
|
||||
void finalize_apply_tactic();
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/elaborate.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
expr mk_assert_tactic_expr(name const & id, expr const & e) {
|
||||
return mk_app(mk_constant(get_tactic_assert_hypothesis_name()),
|
||||
mk_constant(id), e);
|
||||
}
|
||||
|
||||
tactic assert_tactic(elaborate_fn const & elab, name const & id, expr const & e) {
|
||||
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
proof_state new_s = s;
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
bool report_unassigned = true;
|
||||
if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(), report_unassigned)) {
|
||||
goals const & gs = new_s.get_goals();
|
||||
goal const & g = head(gs);
|
||||
expr new_meta1 = g.mk_meta(mk_fresh_name(), *new_e);
|
||||
goal new_goal1(new_meta1, *new_e);
|
||||
expr new_local = mk_local(mk_fresh_name(), id, *new_e, binder_info());
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
hyps.push_back(new_local);
|
||||
expr new_mvar2 = mk_metavar(mk_fresh_name(), Pi(hyps, g.get_type()));
|
||||
hyps.pop_back();
|
||||
expr new_meta2_core = mk_app(new_mvar2, hyps);
|
||||
expr new_meta2 = mk_app(new_meta2_core, new_local);
|
||||
goal new_goal2(new_meta2, g.get_type());
|
||||
substitution new_subst = new_s.get_subst();
|
||||
assign(new_subst, g, mk_app(new_meta2_core, new_meta1));
|
||||
return some_proof_state(proof_state(new_s, cons(new_goal1, cons(new_goal2, tail(gs))), new_subst));
|
||||
}
|
||||
return none_proof_state();
|
||||
});
|
||||
}
|
||||
|
||||
void initialize_assert_tactic() {
|
||||
register_tac(get_tactic_assert_hypothesis_name(),
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
name id = tactic_expr_to_id(app_arg(app_fn(e)), "invalid 'assert' tactic, argument must be an identifier");
|
||||
check_tactic_expr(app_arg(e), "invalid 'assert' tactic, argument must be an expression");
|
||||
return assert_tactic(fn, id, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
}
|
||||
void finalize_assert_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
|
||||
namespace lean {
|
||||
expr mk_assert_tactic_expr(name const & id, expr const & e);
|
||||
tactic assert_tactic(elaborate_fn const & elab, name const & id, expr const & e);
|
||||
void initialize_assert_tactic();
|
||||
void finalize_assert_tactic();
|
||||
}
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "library/constants.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "library/locals.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic clear_tactic(name const & n) {
|
||||
auto fn = [=](environment const &, io_state const &, proof_state const & _s) -> optional<proof_state> {
|
||||
if (!_s.get_goals()) {
|
||||
throw_no_goal_if_enabled(_s);
|
||||
return none_proof_state();
|
||||
}
|
||||
proof_state s = apply_substitution(_s);
|
||||
goals const & gs = s.get_goals();
|
||||
goal g = head(gs);
|
||||
goals tail_gs = tail(gs);
|
||||
if (auto p = g.find_hyp(n)) {
|
||||
expr const & h = p->first;
|
||||
unsigned i = p->second;
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
hyps.erase(hyps.size() - i - 1);
|
||||
if (depends_on(g.get_type(), h)) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'clear' tactic, conclusion depends on '"
|
||||
<< n << "'");
|
||||
return none_proof_state();
|
||||
}
|
||||
if (auto h2 = depends_on(i, hyps.end() - i, h)) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'clear' tactic, hypothesis '" << *h2
|
||||
<< "' depends on '" << n << "'");
|
||||
return none_proof_state();
|
||||
}
|
||||
expr new_type = g.get_type();
|
||||
expr new_meta = mk_app(mk_metavar(mk_fresh_name(), Pi(hyps, new_type)), hyps);
|
||||
goal new_g(new_meta, new_type);
|
||||
substitution new_subst = s.get_subst();
|
||||
assign(new_subst, g, new_meta);
|
||||
proof_state new_s(s, goals(new_g, tail_gs), new_subst);
|
||||
return some_proof_state(new_s);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'clear' tactic, goal does not have a hypothesis "
|
||||
<< " named '" << n << "'");
|
||||
return none_proof_state();
|
||||
}
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
|
||||
void initialize_clear_tactic() {
|
||||
auto fn = [](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
|
||||
buffer<name> ns;
|
||||
get_tactic_id_list_elements(app_arg(e), ns, "invalid 'clears' tactic, list of identifiers expected");
|
||||
tactic r = clear_tactic(ns.back());
|
||||
ns.pop_back();
|
||||
while (!ns.empty()) {
|
||||
r = then(clear_tactic(ns.back()), r);
|
||||
ns.pop_back();
|
||||
}
|
||||
return r;
|
||||
};
|
||||
register_tac(get_tactic_clear_name(), fn);
|
||||
register_tac(get_tactic_clears_name(), fn);
|
||||
}
|
||||
void finalize_clear_tactic() {}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic clear_tactic(name const & n);
|
||||
void initialize_clear_tactic();
|
||||
void finalize_clear_tactic();
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/lazy_list_fn.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/inductive/inductive.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/util.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "library/tactic/apply_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
/**
|
||||
\brief Implement multiple variations of the constructor tactic.
|
||||
It tries to solve the goal by applying the i-th constructor.
|
||||
If \c num_constructors is not none, then the tactic checks wether the inductive datatype has
|
||||
the expected number of constructors.
|
||||
If \c given_args is provided, then the tactic fixes the given arguments.
|
||||
It creates a subgoal for each remaining argument.
|
||||
*/
|
||||
tactic constructor_tactic(elaborate_fn const & elab, optional<unsigned> _i, optional<unsigned> num_constructors,
|
||||
list<expr> const & given_args, bool use_fapply = false) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
constraint_seq cs;
|
||||
auto tc = mk_type_checker(env);
|
||||
goal const & g = head(gs);
|
||||
expr t = tc->whnf(g.get_type(), cs);
|
||||
buffer<expr> I_args;
|
||||
expr I = get_app_args(t, I_args);
|
||||
if (!is_constant(I) || !inductive::is_inductive_decl(env, const_name(I))) {
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'constructor' tactic, goal is not an inductive datatype");
|
||||
return proof_state_seq();
|
||||
}
|
||||
buffer<name> c_names;
|
||||
get_intro_rule_names(env, const_name(I), c_names);
|
||||
if (num_constructors && c_names.size() != *num_constructors) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'constructor' tactic, goal is an inductive datatype, "
|
||||
<< "but it does not have " << *num_constructors << " constructor(s)");
|
||||
return proof_state_seq();
|
||||
}
|
||||
|
||||
auto try_constructor = [&](proof_state const & s, unsigned i) {
|
||||
if (i >= c_names.size()) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'constructor' tactic, goal is an inductive datatype, "
|
||||
<< "but it has only " << c_names.size() << " constructor(s)");
|
||||
return proof_state_seq();
|
||||
}
|
||||
expr C = mk_constant(c_names[i], const_levels(I));
|
||||
unsigned num_params = *inductive::get_num_params(env, const_name(I));
|
||||
if (I_args.size() < num_params)
|
||||
return proof_state_seq();
|
||||
proof_state new_s(s);
|
||||
C = mk_app(C, num_params, I_args.data());
|
||||
expr C_type = tc->whnf(tc->infer(C, cs), cs);
|
||||
bool report_unassigned = true;
|
||||
bool enforce_type = true;
|
||||
for (expr const & arg : given_args) {
|
||||
if (!is_pi(C_type)) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'constructor' tactic, "
|
||||
<< "too many arguments have been provided");
|
||||
return proof_state_seq();
|
||||
}
|
||||
try {
|
||||
if (auto new_arg = elaborate_with_respect_to(env, ios, elab, new_s, arg, some_expr(binding_domain(C_type)),
|
||||
report_unassigned, enforce_type)) {
|
||||
C = mk_app(C, *new_arg);
|
||||
C_type = tc->whnf(instantiate(binding_body(C_type), *new_arg), cs);
|
||||
} else {
|
||||
return proof_state_seq();
|
||||
}
|
||||
} catch (exception &) {
|
||||
if (new_s.report_failure())
|
||||
throw;
|
||||
return proof_state_seq();
|
||||
}
|
||||
}
|
||||
if (use_fapply)
|
||||
return fapply_tactic_core(env, ios, new_s, C, cs);
|
||||
else
|
||||
return apply_tactic_core(env, ios, new_s, C, cs);
|
||||
};
|
||||
|
||||
if (_i) {
|
||||
if (*_i == 0) {
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'constructor' tactic, index must be greater than zero");
|
||||
return proof_state_seq();
|
||||
}
|
||||
return try_constructor(s, *_i - 1);
|
||||
} else {
|
||||
proof_state new_s = s.update_report_failure(false);
|
||||
proof_state_seq r;
|
||||
for (unsigned i = 0; i < c_names.size(); i++)
|
||||
r = append(r, try_constructor(new_s, i));
|
||||
return r;
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
void initialize_constructor_tactic() {
|
||||
register_tac(name{"tactic", "constructor"},
|
||||
[](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
auto i = get_optional_unsigned(tc, app_arg(e));
|
||||
return constructor_tactic(fn, i, optional<unsigned>(), list<expr>());
|
||||
});
|
||||
register_tac(name{"tactic", "fconstructor"},
|
||||
[](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
auto i = get_optional_unsigned(tc, app_arg(e));
|
||||
return constructor_tactic(fn, i, optional<unsigned>(), list<expr>(), true);
|
||||
});
|
||||
register_tac(name{"tactic", "split"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *) {
|
||||
return constructor_tactic(fn, optional<unsigned>(1), optional<unsigned>(1), list<expr>());
|
||||
});
|
||||
register_tac(name{"tactic", "left"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *) {
|
||||
return constructor_tactic(fn, optional<unsigned>(1), optional<unsigned>(2), list<expr>());
|
||||
});
|
||||
register_tac(name{"tactic", "right"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *) {
|
||||
return constructor_tactic(fn, optional<unsigned>(2), optional<unsigned>(2), list<expr>());
|
||||
});
|
||||
register_tac(name{"tactic", "existsi"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'existsi' tactic, invalid argument");
|
||||
expr arg = get_tactic_expr_expr(app_arg(e));
|
||||
return constructor_tactic(fn, optional<unsigned>(1), optional<unsigned>(1), list<expr>(arg));
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_constructor_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
namespace lean {
|
||||
void initialize_constructor_tactic();
|
||||
void finalize_constructor_tactic();
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "kernel/inductive/inductive.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/util.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/intros_tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "kernel/kernel_exception.h"
|
||||
|
||||
namespace lean {
|
||||
tactic contradiction_tactic() {
|
||||
auto fn = [=](environment const & env, io_state const &, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return optional<proof_state>();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
expr const & t = g.get_type();
|
||||
substitution subst = s.get_subst();
|
||||
auto tc = mk_type_checker(env);
|
||||
auto conserv_tc = mk_type_checker(env, UnfoldReducible);
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
for (expr const & h : hyps) {
|
||||
expr h_type = mlocal_type(h);
|
||||
h_type = tc->whnf(h_type).first;
|
||||
expr lhs, rhs, arg;
|
||||
if (is_false(env, h_type)) {
|
||||
assign(subst, g, mk_false_rec(*tc, h, t));
|
||||
return some_proof_state(proof_state(s, tail(gs), subst));
|
||||
} else if (is_not(env, h_type, arg)) {
|
||||
optional<expr> h_pos;
|
||||
for (expr const & h_prime : hyps) {
|
||||
constraint_seq cs;
|
||||
if (conserv_tc->is_def_eq(arg, mlocal_type(h_prime), justification(), cs) && !cs) {
|
||||
h_pos = h_prime;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (h_pos) {
|
||||
assign(subst, g, mk_absurd(*tc, t, *h_pos, h));
|
||||
return some_proof_state(proof_state(s, tail(gs), subst));
|
||||
}
|
||||
} else if (is_eq(h_type, lhs, rhs)) {
|
||||
lhs = tc->whnf(lhs).first;
|
||||
rhs = tc->whnf(rhs).first;
|
||||
optional<name> lhs_c = is_constructor_app(env, lhs);
|
||||
optional<name> rhs_c = is_constructor_app(env, rhs);
|
||||
if (lhs_c && rhs_c && *lhs_c != *rhs_c) {
|
||||
if (optional<name> I_name = inductive::is_intro_rule(env, *lhs_c)) {
|
||||
name no_confusion(*I_name, "no_confusion");
|
||||
try {
|
||||
expr I = tc->whnf(tc->infer(lhs).first).first;
|
||||
buffer<expr> args;
|
||||
expr I_fn = get_app_args(I, args);
|
||||
if (is_constant(I_fn)) {
|
||||
level t_lvl = sort_level(tc->ensure_type(t).first);
|
||||
expr V = mk_app(mk_app(mk_constant(no_confusion, cons(t_lvl, const_levels(I_fn))), args),
|
||||
t, lhs, rhs, h);
|
||||
if (auto r = lift_down_if_hott(*tc, V)) {
|
||||
check_term(*tc, *r);
|
||||
assign(subst, g, *r);
|
||||
return some_proof_state(proof_state(s, tail(gs), subst));
|
||||
}
|
||||
}
|
||||
} catch (kernel_exception & ex) {
|
||||
// TODO(Leo)
|
||||
// regular(env, ios) << ex << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return none_proof_state();
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
|
||||
void initialize_contradiction_tactic() {
|
||||
register_tac(name{"tactic", "contradiction"},
|
||||
[](old_type_checker &, elaborate_fn const &, expr const &, pos_info_provider const *) {
|
||||
list<name> empty;
|
||||
return then(orelse(intros_tactic(empty), id_tactic()), contradiction_tactic());
|
||||
});
|
||||
}
|
||||
void finalize_contradiction_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
namespace lean {
|
||||
void initialize_contradiction_tactic();
|
||||
void finalize_contradiction_tactic();
|
||||
}
|
||||
|
|
@ -1,171 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "kernel/type_checker.h"
|
||||
#include "kernel/for_each_fn.h"
|
||||
#include "kernel/error_msgs.h"
|
||||
#include "library/util.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/elaborate.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
// Return true iff \c e is of the form (?m l_1 ... l_n), where ?m is a metavariable and l_i's local constants
|
||||
bool is_meta_placeholder(expr const & e) {
|
||||
if (!is_meta(e))
|
||||
return false;
|
||||
buffer<expr> args;
|
||||
get_app_args(e, args);
|
||||
return std::all_of(args.begin(), args.end(), is_local);
|
||||
}
|
||||
|
||||
tactic exact_tactic(elaborate_fn const & elab, expr const & e, bool enforce_type_during_elaboration, bool allow_metavars,
|
||||
bool conservative) {
|
||||
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
proof_state new_s = s;
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
expr t = head(gs).get_type();
|
||||
bool report_unassigned = !allow_metavars && enforce_type_during_elaboration && s.report_failure();
|
||||
optional<expr> new_e;
|
||||
try {
|
||||
new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, some_expr(t),
|
||||
report_unassigned, enforce_type_during_elaboration,
|
||||
conservative);
|
||||
} catch (exception &) {
|
||||
if (s.report_failure())
|
||||
throw;
|
||||
else
|
||||
return none_proof_state();
|
||||
}
|
||||
if (new_e) {
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (gs) {
|
||||
goal const & g = head(gs);
|
||||
if (!allow_metavars && has_expr_metavar_relaxed(*new_e)) {
|
||||
throw_tactic_exception_if_enabled(s, [=](formatter const & fmt) {
|
||||
format r = format("invalid 'exact' tactic, term still contains metavariables "
|
||||
"after elaboration");
|
||||
r += pp_indent_expr(fmt, *new_e);
|
||||
return r;
|
||||
});
|
||||
return none_proof_state();
|
||||
}
|
||||
substitution subst = new_s.get_subst();
|
||||
assign(subst, g, *new_e);
|
||||
if (allow_metavars) {
|
||||
buffer<goal> new_goals;
|
||||
auto tc = mk_type_checker(env);
|
||||
for_each(*new_e, [&](expr const & m, unsigned) {
|
||||
if (!has_expr_metavar(m))
|
||||
return false;
|
||||
if (is_meta_placeholder(m)) {
|
||||
new_goals.push_back(goal(m, tc->infer(m).first));
|
||||
return false;
|
||||
}
|
||||
return !is_metavar(m) && !is_local(m);
|
||||
});
|
||||
goals new_gs = to_list(new_goals.begin(), new_goals.end(), tail(gs));
|
||||
return some(proof_state(new_s, new_gs, subst));
|
||||
} else {
|
||||
return some(proof_state(new_s, tail(gs), subst));
|
||||
}
|
||||
} else {
|
||||
return some_proof_state(new_s);
|
||||
}
|
||||
}
|
||||
return none_proof_state();
|
||||
});
|
||||
}
|
||||
|
||||
static tactic assumption_tactic_core(bool conservative) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
proof_state new_s = s.update_report_failure(false);
|
||||
optional<tactic> tac;
|
||||
goal g = head(gs);
|
||||
buffer<expr> hs;
|
||||
g.get_hyps(hs);
|
||||
auto elab = [](goal const &, options const &, expr const & H,
|
||||
optional<expr> const &, substitution const & s, bool) -> elaborate_result {
|
||||
return elaborate_result(H, s, constraints());
|
||||
};
|
||||
unsigned i = hs.size();
|
||||
while (i > 0) {
|
||||
--i;
|
||||
expr const & h = hs[i];
|
||||
tactic curr = exact_tactic(elab, h, false, false, conservative);
|
||||
if (tac) {
|
||||
tac = orelse(*tac, curr);
|
||||
} else {
|
||||
tac = curr;
|
||||
}
|
||||
}
|
||||
if (tac) {
|
||||
return (*tac)(env, ios, s);
|
||||
} else {
|
||||
return proof_state_seq();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
tactic eassumption_tactic() {
|
||||
return assumption_tactic_core(false);
|
||||
}
|
||||
|
||||
tactic assumption_tactic() {
|
||||
return assumption_tactic_core(true);
|
||||
}
|
||||
|
||||
static expr * g_exact_tac_fn = nullptr;
|
||||
static expr * g_rexact_tac_fn = nullptr;
|
||||
static expr * g_refine_tac_fn = nullptr;
|
||||
expr const & get_exact_tac_fn() { return *g_exact_tac_fn; }
|
||||
expr const & get_rexact_tac_fn() { return *g_rexact_tac_fn; }
|
||||
expr const & get_refine_tac_fn() { return *g_refine_tac_fn; }
|
||||
void initialize_exact_tactic() {
|
||||
name const & exact_tac_name = get_tactic_exact_name();
|
||||
name const & rexact_tac_name = get_tactic_rexact_name();
|
||||
name const & refine_tac_name = get_tactic_refine_name();
|
||||
g_exact_tac_fn = new expr(Const(exact_tac_name));
|
||||
g_rexact_tac_fn = new expr(Const(rexact_tac_name));
|
||||
g_refine_tac_fn = new expr(Const(refine_tac_name));
|
||||
register_tac(exact_tac_name,
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'exact' tactic, invalid argument");
|
||||
return exact_tactic(fn, get_tactic_expr_expr(app_arg(e)), true, false, false);
|
||||
});
|
||||
register_tac(rexact_tac_name,
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'rexact' tactic, invalid argument");
|
||||
return exact_tactic(fn, get_tactic_expr_expr(app_arg(e)), false, false, false);
|
||||
});
|
||||
register_tac(refine_tac_name,
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'refine' tactic, invalid argument");
|
||||
return exact_tactic(fn, get_tactic_expr_expr(app_arg(e)), true, true, false);
|
||||
});
|
||||
register_simple_tac(get_tactic_eassumption_name(),
|
||||
[]() { return eassumption_tactic(); });
|
||||
|
||||
register_simple_tac(get_tactic_assumption_name(),
|
||||
[]() { return assumption_tactic(); });
|
||||
}
|
||||
void finalize_exact_tactic() {
|
||||
delete g_exact_tac_fn;
|
||||
delete g_rexact_tac_fn;
|
||||
delete g_refine_tac_fn;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
|
||||
namespace lean {
|
||||
expr const & get_exact_tac_fn();
|
||||
expr const & get_rexact_tac_fn();
|
||||
/** \brief Solve first goal iff it is definitionally equal to type of \c e */
|
||||
void initialize_exact_tactic();
|
||||
void finalize_exact_tactic();
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "kernel/inductive/inductive.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/util.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/intros_tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "kernel/kernel_exception.h"
|
||||
|
||||
namespace lean {
|
||||
tactic exfalso_tactic() {
|
||||
auto fn = [=](environment const & env, io_state const &, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return optional<proof_state>();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
expr const & t = g.get_type();
|
||||
substitution subst = s.get_subst();
|
||||
auto tc = mk_type_checker(env);
|
||||
expr false_expr = mk_false(env);
|
||||
expr new_meta = g.mk_meta(mk_fresh_name(), false_expr);
|
||||
goal new_goal(new_meta, false_expr);
|
||||
assign(subst, g, mk_false_rec(*tc, new_meta, t));
|
||||
return some(proof_state(s, goals(new_goal, tail(gs)), subst));
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
void initialize_exfalso_tactic() {
|
||||
register_tac(name{"tactic", "exfalso"},
|
||||
[](old_type_checker &, elaborate_fn const &, expr const &, pos_info_provider const *) {
|
||||
return exfalso_tactic();
|
||||
});
|
||||
}
|
||||
void finalize_exfalso_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
namespace lean {
|
||||
void initialize_exfalso_tactic();
|
||||
void finalize_exfalso_tactic();
|
||||
}
|
||||
|
|
@ -1,246 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "kernel/inductive/inductive.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/util.h"
|
||||
#include "library/old_util.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/elaborate.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "library/tactic/apply_tactic.h"
|
||||
#include "library/tactic/clear_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic injection_tactic_core(expr const & e, unsigned num, list<name> const & ids, bool report_errors);
|
||||
|
||||
// Return true iff lhs and rhs are of the form (f ...) f is a constructor
|
||||
bool is_injection_target(old_type_checker & tc, expr lhs, expr rhs) {
|
||||
environment const & env = tc.env();
|
||||
lhs = tc.whnf(lhs).first;
|
||||
rhs = tc.whnf(rhs).first;
|
||||
expr A = tc.whnf(tc.infer(lhs).first).first;
|
||||
expr const & I = get_app_fn(A);
|
||||
if (!is_constant(I) || !inductive::is_inductive_decl(env, const_name(I)))
|
||||
return false;
|
||||
expr lhs_fn = get_app_fn(lhs);
|
||||
expr rhs_fn = get_app_fn(rhs);
|
||||
return
|
||||
is_constant(lhs_fn) && is_constant(rhs_fn) &&
|
||||
const_name(lhs_fn) == const_name(rhs_fn) &&
|
||||
inductive::is_intro_rule(env, const_name(lhs_fn));
|
||||
}
|
||||
|
||||
/** \brief Introduce num hypotheses, if _ns is not nil use it to name the hypothesis,
|
||||
|
||||
New hypothesis of the form (a = a) and (a == a) are discarded.
|
||||
New hypothesis of the form (a == b) where (a b : A), are converted into (a = b).
|
||||
*/
|
||||
tactic intros_num_tactic(unsigned num, list<name> _ns) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
if (num == 0)
|
||||
return proof_state_seq(s);
|
||||
list<name> ns = _ns;
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs))
|
||||
return proof_state_seq();
|
||||
goal const & g = head(gs);
|
||||
auto tc = mk_type_checker(env);
|
||||
expr t = g.get_type();
|
||||
expr m = g.get_meta();
|
||||
|
||||
auto mk_name = [&](name const & n) {
|
||||
if (is_nil(ns)) {
|
||||
return g.get_unused_name(n);
|
||||
} else {
|
||||
name r = head(ns);
|
||||
ns = tail(ns);
|
||||
return r;
|
||||
}
|
||||
};
|
||||
|
||||
auto keep_hyp = [&]() {
|
||||
expr H = mk_local(mk_name(binding_name(t)), binding_domain(t));
|
||||
t = instantiate(binding_body(t), H);
|
||||
m = mk_app(m, H);
|
||||
proof_state new_s(s, cons(goal(m, t), tail(gs)));
|
||||
return intros_num_tactic(num-1, ns)(env, ios, new_s);
|
||||
};
|
||||
|
||||
auto discard_hyp = [&]() {
|
||||
expr new_meta = g.mk_meta(mk_fresh_name(), binding_body(t));
|
||||
goal new_goal(new_meta, binding_body(t));
|
||||
substitution new_subst = s.get_subst();
|
||||
assign(new_subst, g, mk_lambda(binding_name(t), binding_domain(t), new_meta));
|
||||
proof_state new_s(s, cons(new_goal, tail(gs)), new_subst);
|
||||
return intros_num_tactic(num-1, ns)(env, ios, new_s);
|
||||
};
|
||||
|
||||
t = tc->ensure_pi(t).first;
|
||||
|
||||
// if goal depends on hypothesis, we keep it
|
||||
if (!closed(binding_body(t)))
|
||||
return keep_hyp();
|
||||
|
||||
constraint_seq cs;
|
||||
expr Htype = tc->whnf(binding_domain(t), cs);
|
||||
|
||||
// new unification constraints were generated, so we keep hypothesis
|
||||
if (cs)
|
||||
return keep_hyp();
|
||||
|
||||
expr lhs, rhs;
|
||||
if (is_eq(Htype, lhs, rhs)) {
|
||||
// equalities of the form (a = a) are discarded
|
||||
if (tc->is_def_eq(lhs, rhs, justification(), cs) && !cs) {
|
||||
return discard_hyp();
|
||||
} else if (is_injection_target(*tc, lhs, rhs)) {
|
||||
// apply injection recursively
|
||||
name Hname = mk_fresh_name();
|
||||
expr H = mk_local(Hname, binding_domain(t));
|
||||
t = binding_body(t);
|
||||
m = mk_app(m, H);
|
||||
proof_state new_s(s, cons(goal(m, t), tail(gs)));
|
||||
return then(injection_tactic_core(H, num-1, ns, false),
|
||||
clear_tactic(Hname))(env, ios, new_s);
|
||||
} else {
|
||||
return keep_hyp();
|
||||
}
|
||||
}
|
||||
|
||||
expr A, B;
|
||||
if (is_standard(env) && is_heq(Htype, A, lhs, B, rhs)) {
|
||||
if (tc->is_def_eq(A, B, justification(), cs) && !cs) {
|
||||
// since types A and B are definitionally equal, we convert to homogeneous
|
||||
expr new_eq = mk_eq(*tc, lhs, rhs);
|
||||
expr new_type = mk_pi(binding_name(t), new_eq, binding_body(t));
|
||||
expr new_meta = g.mk_meta(mk_fresh_name(), new_type);
|
||||
goal new_goal(new_meta, new_type);
|
||||
expr H = mk_local(mk_fresh_name(), binding_domain(t));
|
||||
levels heq_lvl = const_levels(get_app_fn(Htype));
|
||||
expr arg = mk_app(mk_constant(get_eq_of_heq_name(), heq_lvl), A, lhs, rhs, H);
|
||||
expr V = Fun(H, mk_app(new_meta, arg));
|
||||
substitution new_subst = s.get_subst();
|
||||
assign(new_subst, g, V);
|
||||
proof_state new_s(s, cons(new_goal, tail(gs)), new_subst);
|
||||
return intros_num_tactic(num, ns)(env, ios, new_s);
|
||||
} else {
|
||||
return keep_hyp();
|
||||
}
|
||||
}
|
||||
|
||||
// hypothesis is not an equality
|
||||
return keep_hyp();
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
tactic injection_tactic_core(expr const & e, unsigned num, list<name> const & ids, bool report_errors) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
expr t = head(gs).get_type();
|
||||
constraint_seq cs;
|
||||
auto tc = mk_type_checker(env);
|
||||
expr e_type = tc->whnf(tc->infer(e, cs), cs);
|
||||
expr lhs, rhs;
|
||||
if (!is_eq(e_type, lhs, rhs)) {
|
||||
if (report_errors) {
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'injection' tactic, "
|
||||
"given argument is not an equality proof");
|
||||
return proof_state_seq();
|
||||
}
|
||||
return intros_num_tactic(num, ids)(env, ios, s);
|
||||
}
|
||||
lhs = tc->whnf(lhs, cs);
|
||||
rhs = tc->whnf(rhs, cs);
|
||||
expr A = tc->whnf(tc->infer(lhs, cs), cs);
|
||||
buffer<expr> I_args;
|
||||
expr I = get_app_args(A, I_args);
|
||||
if (!is_constant(I) || !inductive::is_inductive_decl(env, const_name(I))) {
|
||||
if (report_errors) {
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'injection' tactic, "
|
||||
"it is not an equality between inductive values");
|
||||
return proof_state_seq();
|
||||
}
|
||||
return intros_num_tactic(num, ids)(env, ios, s);
|
||||
}
|
||||
expr lhs_fn = get_app_fn(lhs);
|
||||
expr rhs_fn = get_app_fn(rhs);
|
||||
if (!is_constant(lhs_fn) || !is_constant(rhs_fn) || const_name(lhs_fn) != const_name(rhs_fn) ||
|
||||
!inductive::is_intro_rule(env, const_name(lhs_fn))) {
|
||||
if (report_errors) {
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'injection' tactic, "
|
||||
"the given equality is not of the form (f ...) = (f ...) "
|
||||
"where f is a constructor");
|
||||
return proof_state_seq();
|
||||
}
|
||||
return intros_num_tactic(num, ids)(env, ios, s);
|
||||
}
|
||||
unsigned num_params = *inductive::get_num_params(env, const_name(I));
|
||||
unsigned cnstr_arity = get_arity(env.get(const_name(lhs_fn)).get_type());
|
||||
lean_assert(cnstr_arity >= num_params);
|
||||
unsigned num_new_eqs = cnstr_arity - num_params;
|
||||
level t_lvl = sort_level(tc->ensure_type(t, cs));
|
||||
expr N = mk_constant(name(const_name(I), "no_confusion"), cons(t_lvl, const_levels(I)));
|
||||
N = mk_app(mk_app(N, I_args), t, lhs, rhs, e);
|
||||
proof_state new_s(s);
|
||||
if (is_standard(env)) {
|
||||
tactic tac = then(take(apply_tactic_core(N, cs), 1),
|
||||
intros_num_tactic(num + num_new_eqs, ids));
|
||||
return tac(env, ios, new_s);
|
||||
} else {
|
||||
level n_lvl = mk_meta_univ(mk_fresh_name());
|
||||
expr lift_down = mk_app(mk_constant(get_lift_down_name(), {t_lvl, n_lvl}), t);
|
||||
tactic tac = then(take(apply_tactic_core(lift_down), 1),
|
||||
then(take(apply_tactic_core(N, cs), 1),
|
||||
intros_num_tactic(num + num_new_eqs, ids)));
|
||||
return tac(env, ios, new_s);
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
};
|
||||
|
||||
tactic injection_tactic(elaborate_fn const & elab, expr const & e, list<name> const & ids) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
proof_state new_s = s;
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
expr t = head(gs).get_type();
|
||||
bool report_unassigned = true;
|
||||
bool enforce_type = false;
|
||||
if (optional<expr> new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(),
|
||||
report_unassigned, enforce_type)) {
|
||||
return injection_tactic_core(*new_e, 0, ids, true)(env, ios, new_s);
|
||||
} else {
|
||||
return proof_state_seq();
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
void initialize_injection_tactic() {
|
||||
register_tac(name{"tactic", "injection"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(app_fn(e)), "invalid 'injection' tactic, invalid argument");
|
||||
buffer<name> ids;
|
||||
get_tactic_id_list_elements(app_arg(e), ids, "invalid 'injection' tactic, list of identifiers expected");
|
||||
return take(injection_tactic(fn, get_tactic_expr_expr(app_arg(app_fn(e))), to_list(ids)), 1);
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_injection_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
namespace lean {
|
||||
void initialize_injection_tactic();
|
||||
void finalize_injection_tactic();
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/tactic/intros_tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
static tactic intro_intros_tactic(list<name> _ns, bool is_intros) {
|
||||
auto fn = [=](environment const & env, io_state const &, proof_state const & s) {
|
||||
list<name> ns = _ns;
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return optional<proof_state>();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
auto tc = mk_type_checker(env);
|
||||
expr t = g.get_type();
|
||||
expr m = g.get_meta();
|
||||
bool gen_names = is_intros && empty(ns);
|
||||
bool gen_one_name = !is_intros && empty(ns);
|
||||
bool first = true;
|
||||
try {
|
||||
while (true) {
|
||||
if (!gen_names && (!gen_one_name || !first) && is_nil(ns))
|
||||
break;
|
||||
if (!is_pi(t)) {
|
||||
if (!is_nil(ns)) {
|
||||
t = tc->ensure_pi(t).first;
|
||||
} else {
|
||||
expr new_t = tc->whnf(t).first;
|
||||
if (!is_pi(new_t))
|
||||
break;
|
||||
t = new_t;
|
||||
}
|
||||
}
|
||||
name new_name;
|
||||
if (!is_nil(ns)) {
|
||||
new_name = head(ns);
|
||||
if (new_name == "_")
|
||||
new_name = get_unused_name(binding_name(t), m);
|
||||
ns = tail(ns);
|
||||
} else {
|
||||
new_name = get_unused_name(binding_name(t), m);
|
||||
}
|
||||
expr new_local = mk_local(mk_fresh_name(), new_name, binding_domain(t), binding_info(t));
|
||||
t = instantiate(binding_body(t), new_local);
|
||||
m = mk_app(m, new_local);
|
||||
first = false;
|
||||
}
|
||||
goal new_g(m, t);
|
||||
return some(proof_state(s, goals(new_g, tail(gs))));
|
||||
} catch (exception &) {
|
||||
return optional<proof_state>();
|
||||
}
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
|
||||
tactic intro_tactic(list<name> const & ns) {
|
||||
return intro_intros_tactic(ns, false);
|
||||
}
|
||||
|
||||
tactic intros_tactic(list<name> const & ns) {
|
||||
return intro_intros_tactic(ns, true);
|
||||
}
|
||||
|
||||
void initialize_intros_tactic() {
|
||||
register_tac(get_tactic_intro_name(),
|
||||
[](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
|
||||
buffer<name> ns;
|
||||
get_tactic_id_list_elements(app_arg(e), ns, "invalid 'intro' tactic, arguments must be identifiers");
|
||||
return intro_tactic(to_list(ns.begin(), ns.end()));
|
||||
});
|
||||
register_tac(get_tactic_intros_name(),
|
||||
[](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
|
||||
buffer<name> ns;
|
||||
get_tactic_id_list_elements(app_arg(e), ns, "invalid 'intros' tactic, arguments must be identifiers");
|
||||
return intros_tactic(to_list(ns.begin(), ns.end()));
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_intros_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
namespace lean {
|
||||
tactic intros_tactic(list<name> const & ns);
|
||||
void initialize_intros_tactic();
|
||||
void finalize_intros_tactic();
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Author: Robert Y. Lewis
|
||||
*/
|
||||
#include "kernel/type_checker.h"
|
||||
#include "library/util.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/normalize.h"
|
||||
#include "library/norm_num.h"
|
||||
#include "library/old_tmp_type_context.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic norm_num_tactic() {
|
||||
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
expr const & c = g.get_type();
|
||||
expr lhs, rhs;
|
||||
if (!is_eq(c, lhs, rhs)) {
|
||||
throw_tactic_exception_if_enabled(s, "norm_num tactic failed, conclusion is not an equality");
|
||||
return none_proof_state();
|
||||
}
|
||||
old_type_checker_ptr rtc = mk_type_checker(env, UnfoldReducible);
|
||||
lhs = normalize(*rtc, lhs);
|
||||
rhs = normalize(*rtc, rhs);
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
try {
|
||||
old_tmp_type_context ctx(env, ios.get_options());
|
||||
ctx.set_local_instances(to_list(hyps));
|
||||
pair<expr, expr> p = mk_norm_num(ctx, lhs);
|
||||
expr new_lhs = p.first;
|
||||
expr new_lhs_pr = p.second;
|
||||
pair<expr, expr> p2 = mk_norm_num(ctx, rhs);
|
||||
expr new_rhs = p2.first;
|
||||
expr new_rhs_pr = p2.second;
|
||||
mpq v_lhs = mpq_of_expr(ctx, new_lhs), v_rhs = mpq_of_expr(ctx, new_rhs);
|
||||
if (v_lhs == v_rhs) {
|
||||
old_type_checker tc(env);
|
||||
expr g_prf = mk_trans(tc, new_lhs_pr, mk_symm(tc, new_rhs_pr));
|
||||
substitution new_subst = s.get_subst();
|
||||
assign(new_subst, g, g_prf);
|
||||
return some_proof_state(proof_state(s, tail(gs), new_subst));
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, "norm_num tactic failed, lhs doesn't match rhs");
|
||||
return none_proof_state();
|
||||
}
|
||||
} catch (exception & ex) {
|
||||
throw_tactic_exception_if_enabled(s, ex.what());
|
||||
return none_proof_state();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void initialize_norm_num_tactic() {
|
||||
register_tac(name{"tactic", "norm_num"},
|
||||
[](old_type_checker &, elaborate_fn const &, expr const &, pos_info_provider const *) {
|
||||
return norm_num_tactic();
|
||||
});
|
||||
}
|
||||
void finalize_norm_num_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Rob Lewis
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace lean {
|
||||
void initialize_norm_num_tactic();
|
||||
void finalize_norm_num_tactic();
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/unifier.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/elaborate.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
expr mk_note_tactic_expr(name const &id, expr const &e) {
|
||||
return mk_app(mk_constant(get_tactic_note_tac_name()),
|
||||
mk_constant(id), e);
|
||||
}
|
||||
|
||||
tactic note_tactic(elaborate_fn const & elab, name const & id, expr const & e) {
|
||||
return tactic01([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
proof_state new_s = s;
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
bool report_unassigned = true;
|
||||
elaborate_result esc = elab(g, ios.get_options(), e, none_expr(), new_s.get_subst(), report_unassigned);
|
||||
expr new_e; substitution new_subst; constraints cs;
|
||||
std::tie(new_e, new_subst, cs) = esc;
|
||||
if (cs)
|
||||
throw_tactic_exception_if_enabled(s, "invalid 'note' tactic, fail to resolve generated constraints");
|
||||
auto tc = mk_type_checker(env);
|
||||
expr new_e_type = tc->infer(new_e).first;
|
||||
expr new_local = mk_local(mk_fresh_name(), id, new_e_type, binder_info());
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
hyps.push_back(new_local);
|
||||
expr new_mvar = mk_metavar(mk_fresh_name(), Pi(hyps, g.get_type()));
|
||||
hyps.pop_back();
|
||||
expr new_meta_core = mk_app(new_mvar, hyps);
|
||||
expr new_meta = mk_app(new_meta_core, new_local);
|
||||
goal new_goal(new_meta, g.get_type());
|
||||
assign(new_subst, g, mk_app(new_meta_core, new_e));
|
||||
return some_proof_state(proof_state(s, cons(new_goal, tail(gs)), new_subst));
|
||||
});
|
||||
}
|
||||
|
||||
void initialize_note_tactic() {
|
||||
register_tac(get_tactic_note_tac_name(),
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
name id = tactic_expr_to_id(app_arg(app_fn(e)), "invalid 'note' tactic, argument must be an identifier");
|
||||
check_tactic_expr(app_arg(e), "invalid 'note' tactic, argument must be an expression");
|
||||
return note_tactic(fn, id, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
}
|
||||
void finalize_note_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "kernel/expr.h"
|
||||
|
||||
namespace lean {
|
||||
expr mk_note_tactic_expr(name const &id, expr const &e);
|
||||
void initialize_note_tactic();
|
||||
void finalize_note_tactic();
|
||||
}
|
||||
|
|
@ -1,99 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "kernel/instantiate.h"
|
||||
#include "library/relation_manager.h"
|
||||
#include "library/explicit.h"
|
||||
#include "library/placeholder.h"
|
||||
#include "library/tactic/apply_tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
// Remark: if no_meta == true, then return none if goal contains metavariables
|
||||
static optional<name> get_goal_op(proof_state const & s, bool no_meta = false) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return optional<name>();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
if (no_meta && has_metavar(g.get_type()))
|
||||
return optional<name>();
|
||||
expr op = get_app_fn(head_beta_reduce(g.get_type()));
|
||||
if (is_constant(op))
|
||||
return optional<name>(const_name(op));
|
||||
else
|
||||
return optional<name>();
|
||||
}
|
||||
|
||||
tactic refl_tactic(elaborate_fn const & elab, bool no_meta = false) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
auto op = get_goal_op(s, no_meta);
|
||||
if (!op)
|
||||
return proof_state_seq();
|
||||
if (auto refl = get_refl_info(env, *op)) {
|
||||
return apply_tactic(elab, mk_constant(*refl))(env, ios, s);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'reflexivity' tactic, operator '" << *op << "' is not marked are reflexive");
|
||||
return proof_state_seq();
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
tactic symm_tactic(elaborate_fn const & elab) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
auto op = get_goal_op(s);
|
||||
if (!op)
|
||||
return proof_state_seq();
|
||||
if (auto symm = get_symm_info(env, *op)) {
|
||||
return apply_tactic(elab, mk_constant(*symm))(env, ios, s);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'symmetry' tactic, operator '" << *op << "' is not marked are symmetric");
|
||||
return proof_state_seq();
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
tactic trans_tactic(elaborate_fn const & elab, expr const & e) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
auto op = get_goal_op(s);
|
||||
if (!op)
|
||||
return proof_state_seq();
|
||||
if (auto info = get_trans_extra_info(env, *op, *op)) {
|
||||
expr pr = mk_explicit(mk_constant(info->m_name));
|
||||
unsigned nargs = info->m_num_args;
|
||||
lean_assert(nargs >= 5);
|
||||
for (unsigned i = 0; i < nargs - 4; i++)
|
||||
pr = mk_app(pr, mk_expr_placeholder());
|
||||
pr = mk_app(pr, e);
|
||||
return apply_tactic(elab, pr)(env, ios, s);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'transitivity' tactic, operator '" << *op << "' is not marked are transitive");
|
||||
return proof_state_seq();
|
||||
}
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
void initialize_relation_tactics() {
|
||||
register_tac(name{"tactic", "reflexivity"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *) {
|
||||
return refl_tactic(fn);
|
||||
});
|
||||
register_tac(name{"tactic", "symmetry"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *) {
|
||||
return symm_tactic(fn);
|
||||
});
|
||||
register_tac(name{"tactic", "transitivity"},
|
||||
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
check_tactic_expr(app_arg(e), "invalid 'transitivity' tactic, invalid argument");
|
||||
return trans_tactic(fn, get_tactic_expr_expr(app_arg(e)));
|
||||
});
|
||||
}
|
||||
void finalize_relation_tactics() {}
|
||||
}
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
namespace lean {
|
||||
tactic refl_tactic(elaborate_fn const & elab, bool no_meta = false);
|
||||
void initialize_relation_tactics();
|
||||
void finalize_relation_tactics();
|
||||
}
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "library/constants.h"
|
||||
#include "kernel/replace_fn.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic rename_tactic(name const & from, name const & to) {
|
||||
return tactic01([=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
goals const & rest_gs = tail(gs);
|
||||
buffer<expr> locals;
|
||||
get_app_args(g.get_meta(), locals);
|
||||
unsigned i = locals.size();
|
||||
optional<expr> from_local;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
expr const & local = locals[i];
|
||||
if (local_pp_name(local) == from) {
|
||||
from_local = local;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!from_local)
|
||||
return none_proof_state();
|
||||
expr to_local = mk_local(mlocal_name(*from_local), to, mlocal_type(*from_local), local_info(*from_local));
|
||||
auto fn = [&](expr const & e) {
|
||||
if (is_local(e) && mlocal_name(e) == mlocal_name(*from_local))
|
||||
return some_expr(to_local);
|
||||
else
|
||||
return none_expr();
|
||||
};
|
||||
goal new_g(replace(g.get_meta(), fn), replace(g.get_type(), fn));
|
||||
return some(proof_state(s, goals(new_g, rest_gs)));
|
||||
});
|
||||
}
|
||||
|
||||
static name const & get_rename_arg(expr const & e) {
|
||||
return tactic_expr_to_id(e, "invalid 'rename' tactic, arguments must be identifiers");
|
||||
}
|
||||
|
||||
void initialize_rename_tactic() {
|
||||
auto fn = [](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
|
||||
return rename_tactic(get_rename_arg(app_arg(app_fn(e))),
|
||||
get_rename_arg(app_arg(e)));
|
||||
};
|
||||
register_tac(get_tactic_rename_name(), fn);
|
||||
}
|
||||
|
||||
void finalize_rename_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic rename_tactic(name const & from, name const & to);
|
||||
void initialize_rename_tactic();
|
||||
void finalize_rename_tactic();
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Robert Y. Lewis. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Robert Y. Lewis
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "util/lazy_list_fn.h"
|
||||
#include "kernel/error_msgs.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/unifier.h"
|
||||
#include "library/tactic/replace_tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
|
||||
|
||||
static expr * g_replace_tac = nullptr;
|
||||
|
||||
expr substitute_at_occurrences(environment const & env, expr const & t, expr const & nexpr, expr const & oexpr, occurrence const & occ) {
|
||||
bool has_dep_elim = inductive::has_dep_elim(env, get_eq_name());
|
||||
unsigned vidx = has_dep_elim ? 1 : 0;
|
||||
optional<expr> nt = replace_occurrences(t, oexpr, occ, vidx);
|
||||
if (!nt) {
|
||||
return t;
|
||||
}
|
||||
expr t2 = instantiate(*nt, vidx, nexpr);
|
||||
return t2;
|
||||
}
|
||||
|
||||
tactic mk_replace_tactic(elaborate_fn const & elab, expr const & e) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
buffer<expr> e_args;
|
||||
get_app_args(e, e_args);
|
||||
expr t1, t2; // replace t2 with t1
|
||||
location loc;
|
||||
if (e_args.size() == 3) {
|
||||
t1 = get_tactic_expr_expr(e_args[1]);
|
||||
t2 = get_tactic_expr_expr(e_args[0]);
|
||||
if (is_location_expr(get_tactic_expr_expr(e_args[2]))) {
|
||||
loc = get_location_expr_location(get_tactic_expr_expr(e_args[2]));
|
||||
} else {
|
||||
loc = location();
|
||||
}
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, "malformed arguments to replace");
|
||||
return proof_state_seq();
|
||||
}
|
||||
proof_state new_s = s;
|
||||
goals const & gs = new_s.get_goals();
|
||||
if (!gs) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return proof_state_seq();
|
||||
}
|
||||
expr t = head(gs).get_type();
|
||||
bool report_unassigned = true;
|
||||
auto new_t1 = elaborate_with_respect_to(env, ios, elab, new_s, t1, none_expr(), report_unassigned);
|
||||
auto new_t2 = elaborate_with_respect_to(env, ios, elab, new_s, t2, none_expr(), report_unassigned);
|
||||
if (new_t1 && new_t2) {
|
||||
goals const & gs = new_s.get_goals();
|
||||
goal const & g = head(gs);
|
||||
substitution subst = new_s.get_subst();
|
||||
auto tc = mk_type_checker(env);
|
||||
constraint_seq cs;
|
||||
if (tc->is_def_eq(*new_t1, *new_t2, justification(), cs)) {
|
||||
auto nocc = loc.includes_goal();
|
||||
expr new_goal;
|
||||
if (nocc) {
|
||||
new_goal = substitute_at_occurrences(env, g.get_type(), *new_t1, *new_t2, *nocc);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, "replacing in hypotheses not implemented");
|
||||
return proof_state_seq();
|
||||
}
|
||||
if (cs) {
|
||||
unifier_config cfg(ios.get_options());
|
||||
buffer<constraint> cs_buf;
|
||||
cs.linearize(cs_buf);
|
||||
to_buffer(new_s.get_postponed(), cs_buf);
|
||||
unify_result_seq rseq = unify(env, cs_buf.size(), cs_buf.data(), subst, cfg);
|
||||
return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state {
|
||||
substitution const & subst = p.first;
|
||||
constraints const & postponed = p.second;
|
||||
substitution new_subst = subst;
|
||||
expr M = g.mk_meta(mk_fresh_name(), new_goal);
|
||||
goal new_g(M, new_goal);
|
||||
assign(new_subst, g, M);
|
||||
return proof_state(new_s, cons(new_g, tail(gs)), new_subst, postponed);
|
||||
});
|
||||
}
|
||||
expr M = g.mk_meta(mk_fresh_name(), new_goal);
|
||||
goal new_g(M, new_goal);
|
||||
assign(subst, g, M);
|
||||
return proof_state_seq(proof_state(new_s, cons(new_g, tail(gs)), subst));
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(new_s, [=](formatter const & fmt) {
|
||||
format r = format("invalid 'replace' tactic, the new type");
|
||||
r += pp_indent_expr(fmt, *new_t1);
|
||||
r += compose(line(), format("does not match the old type"));
|
||||
r += pp_indent_expr(fmt, *new_t2);
|
||||
return r;
|
||||
});
|
||||
return proof_state_seq();
|
||||
}
|
||||
}
|
||||
return proof_state_seq();
|
||||
});
|
||||
}
|
||||
|
||||
void initialize_replace_tactic() {
|
||||
name replace_tac_name{"tactic", "replace"};
|
||||
g_replace_tac = new expr(Const(replace_tac_name));
|
||||
register_tac(replace_tac_name,
|
||||
[](old_type_checker &, elaborate_fn const & elab, expr const & e, pos_info_provider const *) {
|
||||
return mk_replace_tactic(elab, e);
|
||||
});
|
||||
}
|
||||
|
||||
void finalize_replace_tactic() {
|
||||
delete g_replace_tac;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Robert Y. Lewis. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Robert Y. Lewis
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/location.h"
|
||||
|
||||
namespace lean {
|
||||
|
||||
void initialize_replace_tactic();
|
||||
void finalize_replace_tactic();
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/locals.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic revert_tactic(name const & n) {
|
||||
auto fn = [=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
throw_no_goal_if_enabled(s);
|
||||
return none_proof_state();
|
||||
}
|
||||
goal g = head(gs);
|
||||
goals tail_gs = tail(gs);
|
||||
if (auto p = g.find_hyp(n)) {
|
||||
expr const & h = p->first;
|
||||
unsigned i = p->second;
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
hyps.erase(hyps.size() - i - 1);
|
||||
if (optional<expr> other_h = depends_on(i, hyps.end() - i, h)) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'revert' tactic, hypothesis '" << local_pp_name(*other_h)
|
||||
<< "' depends on '" << local_pp_name(h) << "'");
|
||||
return none_proof_state(); // other hypotheses depend on h
|
||||
}
|
||||
expr new_type = Pi(h, g.get_type());
|
||||
expr new_meta = mk_app(mk_metavar(mk_fresh_name(), Pi(hyps, new_type)), hyps);
|
||||
goal new_g(new_meta, new_type);
|
||||
substitution new_subst = s.get_subst();
|
||||
assign(new_subst, g, mk_app(new_meta, h));
|
||||
proof_state new_s(s, goals(new_g, tail_gs), new_subst);
|
||||
return some_proof_state(new_s);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'revert' tactic, unknown hypothesis '" << n << "'");
|
||||
return none_proof_state();
|
||||
}
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
|
||||
void initialize_revert_tactic() {
|
||||
auto fn = [](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
|
||||
buffer<name> ns;
|
||||
get_tactic_id_list_elements(app_arg(e), ns, "invalid 'reverts' tactic, list of identifiers expected");
|
||||
tactic r = revert_tactic(ns[0]);
|
||||
for (unsigned i = 1; i < ns.size(); i++)
|
||||
r = then(revert_tactic(ns[i]), r);
|
||||
return r;
|
||||
};
|
||||
register_tac(get_tactic_revert_name(), fn);
|
||||
register_tac(get_tactic_reverts_name(), fn);
|
||||
}
|
||||
void finalize_revert_tactic() {}
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/tactic.h"
|
||||
|
||||
namespace lean {
|
||||
tactic revert_tactic(name const & n);
|
||||
void initialize_revert_tactic();
|
||||
void finalize_revert_tactic();
|
||||
}
|
||||
|
|
@ -1,256 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include "util/fresh_name.h"
|
||||
#include "kernel/abstract.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/inductive/inductive.h"
|
||||
#include "kernel/kernel_exception.h"
|
||||
#include "library/constants.h"
|
||||
#include "library/reducible.h"
|
||||
#include "library/util.h"
|
||||
#include "library/locals.h"
|
||||
#include "library/tactic/expr_to_tactic.h"
|
||||
#include "library/tactic/relation_tactics.h"
|
||||
#include "library/tactic/proof_state.h"
|
||||
|
||||
namespace lean {
|
||||
static void split_deps(buffer<expr> const & hyps, expr const & x, expr const & h,
|
||||
buffer<expr> & non_deps, buffer<expr> & deps, bool & depends_on_h) {
|
||||
for (expr const & hyp : hyps) {
|
||||
if (hyp == h || hyp == x) {
|
||||
// we clear h and x
|
||||
} else if (depends_on(hyp, h)) {
|
||||
deps.push_back(hyp);
|
||||
depends_on_h = true;
|
||||
} else if (depends_on(hyp, x) || depends_on_any(hyp, deps)) {
|
||||
deps.push_back(hyp);
|
||||
} else {
|
||||
non_deps.push_back(hyp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optional<proof_state> subst(environment const & env, name const & h_name, bool symm, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs))
|
||||
return none_proof_state();
|
||||
goal g = head(gs);
|
||||
auto opt_h = g.find_hyp_from_internal_name(h_name);
|
||||
if (!opt_h)
|
||||
return none_proof_state();
|
||||
expr const & h = opt_h->first;
|
||||
expr lhs, rhs;
|
||||
if (!is_eq(mlocal_type(h), lhs, rhs))
|
||||
return none_proof_state();
|
||||
auto tc = mk_type_checker(env);
|
||||
if (symm)
|
||||
std::swap(lhs, rhs);
|
||||
if (!is_local(lhs))
|
||||
return none_proof_state();
|
||||
if (depends_on(rhs, lhs)) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'subst' tactic, '" << lhs
|
||||
<< "' occurs in the other side of the equation");
|
||||
return none_proof_state();
|
||||
}
|
||||
buffer<expr> hyps, deps, non_deps;
|
||||
g.get_hyps(hyps);
|
||||
bool depends_on_h = depends_on(g.get_type(), h);
|
||||
split_deps(hyps, lhs, h, non_deps, deps, depends_on_h);
|
||||
// revert dependencies
|
||||
expr type = Pi(deps, g.get_type());
|
||||
// substitute
|
||||
bool has_dep_elim = inductive::has_dep_elim(env, get_eq_name());
|
||||
bool use_dep_elim = has_dep_elim;
|
||||
if (depends_on_h)
|
||||
use_dep_elim = true;
|
||||
expr motive, new_type;
|
||||
new_type = instantiate(abstract_local(type, mlocal_name(lhs)), rhs);
|
||||
if (use_dep_elim) {
|
||||
new_type = instantiate(abstract_local(new_type, mlocal_name(h)), mk_refl(*tc, rhs));
|
||||
if (symm) {
|
||||
motive = Fun(lhs, Fun(h, type));
|
||||
} else {
|
||||
expr Heq = mk_local(mk_fresh_name(), local_pp_name(h), mk_eq(*tc, rhs, lhs), binder_info());
|
||||
motive = Fun(lhs, Fun(Heq, type));
|
||||
}
|
||||
} else {
|
||||
motive = Fun(lhs, type);
|
||||
}
|
||||
buffer<expr> new_hyps;
|
||||
buffer<expr> intros_hyps;
|
||||
new_hyps.append(non_deps);
|
||||
|
||||
// reintroduce dependencies
|
||||
expr new_goal_type = new_type;
|
||||
for (expr const & d : deps) {
|
||||
if (!is_pi(new_goal_type))
|
||||
return none_proof_state();
|
||||
expr new_h = mk_local(mk_fresh_name(), local_pp_name(d), binding_domain(new_goal_type), binder_info());
|
||||
new_hyps.push_back(new_h);
|
||||
intros_hyps.push_back(new_h);
|
||||
new_goal_type = instantiate(binding_body(new_goal_type), new_h);
|
||||
}
|
||||
|
||||
// create new goal
|
||||
expr new_metavar = mk_metavar(mk_fresh_name(), Pi(new_hyps, new_goal_type));
|
||||
expr new_meta_core = mk_app(new_metavar, non_deps);
|
||||
expr new_meta = mk_app(new_meta_core, intros_hyps);
|
||||
goal new_g(new_meta, new_goal_type);
|
||||
// create eqrec term
|
||||
substitution new_subst = s.get_subst();
|
||||
expr major = symm ? h : mk_symm(*tc, h);
|
||||
expr minor = new_meta_core;
|
||||
expr A = tc->infer(lhs).first;
|
||||
level l1 = sort_level(tc->ensure_type(new_type).first);
|
||||
level l2 = sort_level(tc->ensure_type(A).first);
|
||||
name eq_rec_name;
|
||||
if (!has_dep_elim && use_dep_elim)
|
||||
eq_rec_name = get_eq_drec_name();
|
||||
else
|
||||
eq_rec_name = get_eq_rec_name();
|
||||
expr eqrec = mk_app({mk_constant(eq_rec_name, {l1, l2}), A, rhs, motive, minor, lhs, major});
|
||||
if (use_dep_elim) {
|
||||
try {
|
||||
check_term(env, g.abstract(eqrec));
|
||||
} catch (kernel_exception & ex) {
|
||||
if (!s.report_failure())
|
||||
return none_proof_state();
|
||||
std::shared_ptr<kernel_exception> saved_ex(static_cast<kernel_exception*>(ex.clone()));
|
||||
throw tactic_exception("rewrite step failed", none_expr(), s,
|
||||
[=](formatter const & fmt) {
|
||||
format r;
|
||||
r += format("invalid 'subst' tactic, "
|
||||
"produced type incorrect term, details: ");
|
||||
r += saved_ex->pp(fmt);
|
||||
r += line();
|
||||
return r;
|
||||
});
|
||||
}
|
||||
}
|
||||
expr new_val = mk_app(eqrec, deps);
|
||||
assign(new_subst, g, new_val);
|
||||
lean_assert(new_subst.is_assigned(g.get_mvar()));
|
||||
proof_state new_s(s, goals(new_g, tail(gs)), new_subst);
|
||||
return some_proof_state(new_s);
|
||||
}
|
||||
|
||||
tactic mk_subst_tactic_core(name const & h_name, bool symm) {
|
||||
auto fn = [=](environment const & env, io_state const &, proof_state const & s) {
|
||||
return subst(env, h_name, symm, s);
|
||||
};
|
||||
return tactic01(fn);
|
||||
}
|
||||
|
||||
tactic mk_subst_tactic(list<name> const & ids) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
if (!ids)
|
||||
return proof_state_seq(s);
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs))
|
||||
return proof_state_seq();
|
||||
goal const & g = head(gs);
|
||||
name const & id = head(ids);
|
||||
|
||||
auto apply_rewrite = [&](expr const & H, bool symm) {
|
||||
tactic tac = then(mk_subst_tactic_core(mlocal_name(H), symm), mk_subst_tactic(tail(ids)));
|
||||
return tac(env, ios, s);
|
||||
};
|
||||
|
||||
optional<pair<expr, unsigned>> p = g.find_hyp(id);
|
||||
if (!p) {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'subst' tactic, there is no hypothesis named '"
|
||||
<< id << "'");
|
||||
return proof_state_seq();
|
||||
}
|
||||
expr const & H = p->first;
|
||||
expr lhs, rhs;
|
||||
if (is_eq(mlocal_type(H), lhs, rhs)) {
|
||||
if (is_local(rhs)) {
|
||||
return apply_rewrite(H, true);
|
||||
} else if (is_local(lhs)) {
|
||||
return apply_rewrite(H, false);
|
||||
} else {
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'subst' tactic, hypothesis '"
|
||||
<< id << "' is not of the form (x = t) or (t = x)");
|
||||
return proof_state_seq();
|
||||
}
|
||||
} else if (is_local(H)) {
|
||||
expr const & x = H;
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
for (expr const & H : hyps) {
|
||||
expr lhs, rhs;
|
||||
if (is_eq(mlocal_type(H), lhs, rhs)) {
|
||||
if (is_local(lhs) && mlocal_name(lhs) == mlocal_name(x) && !depends_on(rhs, lhs)) {
|
||||
return apply_rewrite(H, false);
|
||||
} else if (is_local(rhs) && mlocal_name(rhs) == mlocal_name(x) && !depends_on(lhs, rhs)) {
|
||||
return apply_rewrite(H, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'subst' tactic, hypothesis '"
|
||||
<< id << "' is not a variable nor an equation of the form (x = t) or (t = x)");
|
||||
return proof_state_seq();
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
tactic mk_subst_vars_tactic(bool first, unsigned start) {
|
||||
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals const & gs = s.get_goals();
|
||||
if (empty(gs)) {
|
||||
if (first)
|
||||
return proof_state_seq();
|
||||
else
|
||||
return proof_state_seq(s);
|
||||
}
|
||||
goal const & g = head(gs);
|
||||
|
||||
auto apply_rewrite = [&](expr const & H, bool symm, unsigned i) {
|
||||
tactic tac = orelse(then(mk_subst_tactic_core(mlocal_name(H), symm), mk_subst_vars_tactic(false, 0)),
|
||||
mk_subst_vars_tactic(false, i+1));
|
||||
return tac(env, ios, s);
|
||||
};
|
||||
|
||||
buffer<expr> hyps;
|
||||
g.get_hyps(hyps);
|
||||
for (unsigned i = start; i < hyps.size(); i++) {
|
||||
expr const & h = hyps[i];
|
||||
expr lhs, rhs;
|
||||
if (is_eq(mlocal_type(h), lhs, rhs)) {
|
||||
if (is_local(rhs)) {
|
||||
return apply_rewrite(h, true, i);
|
||||
} else if (is_local(lhs)) {
|
||||
return apply_rewrite(h, false, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (first)
|
||||
return proof_state_seq();
|
||||
else
|
||||
return proof_state_seq(s);
|
||||
};
|
||||
return tactic(fn);
|
||||
}
|
||||
|
||||
void initialize_subst_tactic() {
|
||||
register_tac(name{"tactic", "subst"},
|
||||
[](old_type_checker &, elaborate_fn const & elab, expr const & e, pos_info_provider const *) {
|
||||
buffer<name> ns;
|
||||
get_tactic_id_list_elements(app_arg(e), ns, "invalid 'subst' tactic, list of identifiers expected");
|
||||
return then(mk_subst_tactic(to_list(ns)), try_tactic(refl_tactic(elab)));
|
||||
});
|
||||
register_tac(name{"tactic", "substvars"},
|
||||
[](old_type_checker &, elaborate_fn const & elab, expr const &, pos_info_provider const *) {
|
||||
return then(mk_subst_vars_tactic(true, 0), try_tactic(refl_tactic(elab)));
|
||||
});
|
||||
}
|
||||
void finalize_subst_tactic() {
|
||||
}
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include "library/tactic/proof_state.h"
|
||||
namespace lean {
|
||||
optional<proof_state> subst(environment const & env, name const & h_name, bool symm, proof_state const & s);
|
||||
void initialize_subst_tactic();
|
||||
void finalize_subst_tactic();
|
||||
}
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#include <utility>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include "util/sstream.h"
|
||||
#include "util/interrupt.h"
|
||||
#include "util/lazy_list_fn.h"
|
||||
#include "util/list_fn.h"
|
||||
#include "kernel/instantiate.h"
|
||||
#include "kernel/type_checker.h"
|
||||
#include "kernel/for_each_fn.h"
|
||||
#include "kernel/replace_fn.h"
|
||||
#include "library/normalize.h"
|
||||
#include "library/util.h"
|
||||
#include "library/old_util.h"
|
||||
#include "library/tactic/tactic.h"
|
||||
#include "library/io_state_stream.h"
|
||||
|
||||
namespace lean {
|
||||
/** \brief Throw an exception is \c v contains local constants, \c e is only used for position information. */
|
||||
void check_has_no_local(expr const & v, expr const & e, char const * tac_name) {
|
||||
if (has_local(v)) {
|
||||
for_each(v, [&](expr const & l, unsigned) {
|
||||
if (is_local(l))
|
||||
throw tactic_exception(e, sstream() << "tactic '" << tac_name << "' contains reference to local '" << local_pp_name(l)
|
||||
<< "' which is not visible by this tactic "
|
||||
<< "possible causes: it was not marked as [visible]; it was destructued");
|
||||
return has_local(l);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
tactic_exception::tactic_exception(char const * msg, optional<expr> const & m, pp_fn const & fn):
|
||||
generic_exception(msg, m, fn) {}
|
||||
tactic_exception::tactic_exception(char const * msg, optional<expr> const & m, proof_state const & ps, pp_fn const & fn):
|
||||
generic_exception(msg, m, fn), m_ps(ps) {}
|
||||
tactic_exception::tactic_exception(expr const & e, std::string const & msg):
|
||||
generic_exception(msg.c_str(), some_expr(e), [=](formatter const &) { return format(msg); }) {}
|
||||
tactic_exception::tactic_exception(std::string const & msg):
|
||||
generic_exception(msg.c_str(), none_expr(), [=](formatter const &) { return format(msg); }) {}
|
||||
tactic_exception::tactic_exception(char const * msg):tactic_exception(std::string(msg)) {}
|
||||
tactic_exception::tactic_exception(sstream const & strm):tactic_exception(strm.str()) {}
|
||||
tactic_exception::tactic_exception(expr const & e, char const * msg):tactic_exception(e, std::string(msg)) {}
|
||||
tactic_exception::tactic_exception(expr const & e, sstream const & strm):tactic_exception(e, strm.str()) {}
|
||||
tactic_exception::tactic_exception(expr const & e, pp_fn const & fn):generic_exception("tactic exception", some_expr(e), fn) {}
|
||||
tactic_exception::tactic_exception(pp_fn const & fn):generic_exception("tactic exception", none_expr(), fn) {}
|
||||
|
||||
void throw_no_goal_if_enabled(proof_state const & ps) {
|
||||
throw_tactic_exception_if_enabled(ps, "invalid tactic, there are no goals to be solved");
|
||||
}
|
||||
|
||||
tactic tactic01(std::function<optional<proof_state>(environment const &, io_state const & ios, proof_state const &)> f) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
return mk_proof_state_seq([=]() {
|
||||
auto r = f(env, ios, s);
|
||||
if (r)
|
||||
return some(mk_pair(*r, proof_state_seq()));
|
||||
else
|
||||
return proof_state_seq::maybe_pair();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
tactic tactic1(std::function<proof_state(environment const &, io_state const & ios, proof_state const &)> f) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
||||
return mk_proof_state_seq([=]() {
|
||||
auto r = f(env, ios, s);
|
||||
return some(mk_pair(r, proof_state_seq()));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
tactic id_tactic() {
|
||||
return tactic1([](environment const &, io_state const &, proof_state const & s) -> proof_state { return s; });
|
||||
}
|
||||
|
||||
tactic fail_tactic() {
|
||||
return tactic([](environment const &, io_state const &, proof_state const &) -> proof_state_seq { return proof_state_seq(); });
|
||||
}
|
||||
|
||||
tactic now_tactic() {
|
||||
return tactic01([](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
||||
if (!empty(s.get_goals()))
|
||||
return none_proof_state();
|
||||
else
|
||||
return some(s);
|
||||
});
|
||||
}
|
||||
|
||||
tactic cond(proof_state_pred p, tactic const & t1, tactic const & t2) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
||||
return mk_proof_state_seq([=]() {
|
||||
if (p(env, ios, s)) {
|
||||
return t1(env, ios, s).pull();
|
||||
} else {
|
||||
return t2(env, ios, s).pull();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
tactic then(tactic const & t1, tactic const & t2) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s1) -> proof_state_seq {
|
||||
return map_append(t1(env, ios, s1), [=](proof_state const & s2) {
|
||||
check_interrupted();
|
||||
bool has_meta = false;
|
||||
goals const & gs = s2.get_goals();
|
||||
for (goal const & g : gs) {
|
||||
if (has_expr_metavar_relaxed(g.get_type())) {
|
||||
has_meta = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_meta) {
|
||||
buffer<goal> gs;
|
||||
substitution subst = s2.get_subst();
|
||||
to_buffer(s2.get_goals(), gs);
|
||||
for (unsigned i = 0; i < gs.size(); i++) {
|
||||
gs[i] = gs[i].instantiate(subst);
|
||||
}
|
||||
proof_state new_s2(s2, to_list(gs));
|
||||
return t2(env, ios, new_s2);
|
||||
} else {
|
||||
return t2(env, ios, s2);
|
||||
}
|
||||
}, "THEN tactical");
|
||||
});
|
||||
}
|
||||
|
||||
tactic orelse(tactic const & t1, tactic const & t2) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s) -> proof_state_seq {
|
||||
proof_state s = _s.update_report_failure(false);
|
||||
return orelse(t1(env, ios, s), t2(env, ios, s), "ORELSE tactical");
|
||||
});
|
||||
}
|
||||
|
||||
tactic using_params(tactic const & t, options const & opts) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
||||
io_state new_ios(ios);
|
||||
new_ios.set_options(join(opts, ios.get_options()));
|
||||
return t(env, new_ios, s);
|
||||
});
|
||||
}
|
||||
|
||||
proof_state rotate_left(proof_state const & s, unsigned n) {
|
||||
buffer<goal> gs;
|
||||
to_buffer(s.get_goals(), gs);
|
||||
unsigned sz = gs.size();
|
||||
if (sz == 0)
|
||||
return s;
|
||||
n = n%sz;
|
||||
std::rotate(gs.begin(), gs.begin() + n, gs.end());
|
||||
return proof_state(s, to_list(gs.begin(), gs.end()));
|
||||
}
|
||||
|
||||
tactic rotate_left(unsigned n) {
|
||||
return tactic1([=](environment const &, io_state const &, proof_state const & s) -> proof_state {
|
||||
return rotate_left(s, n);
|
||||
});
|
||||
}
|
||||
|
||||
tactic rotate_right(unsigned n) {
|
||||
return tactic1([=](environment const &, io_state const &, proof_state const & s) -> proof_state {
|
||||
unsigned ngoals = length(s.get_goals());
|
||||
if (ngoals == 0)
|
||||
return s;
|
||||
return rotate_left(s, ngoals - n%ngoals);
|
||||
});
|
||||
}
|
||||
|
||||
tactic try_for(tactic const & t, unsigned ms, unsigned check_ms) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s) -> proof_state_seq {
|
||||
proof_state s = _s.update_report_failure(false);
|
||||
return timeout(t(env, ios, s), ms, check_ms);
|
||||
});
|
||||
}
|
||||
|
||||
tactic par(tactic const & t1, tactic const & t2, unsigned check_ms) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s) -> proof_state_seq {
|
||||
proof_state s = _s.update_report_failure(false);
|
||||
return par(t1(env, ios, s), t2(env, ios, s), check_ms);
|
||||
});
|
||||
}
|
||||
|
||||
tactic repeat(tactic const & t) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s1) -> proof_state_seq {
|
||||
proof_state s1 = _s1.update_report_failure(false);
|
||||
return repeat(s1, [=](proof_state const & s2) {
|
||||
return t(env, ios, s2);
|
||||
}, "REPEAT tactical");
|
||||
});
|
||||
}
|
||||
|
||||
tactic repeat_at_most(tactic const & t, unsigned k) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s1) -> proof_state_seq {
|
||||
proof_state s1 = _s1.update_report_failure(false);
|
||||
return repeat_at_most(s1, [=](proof_state const & s2) {
|
||||
return t(env, ios, s2);
|
||||
}, k, "REPEAT_AT_MOST tactical");
|
||||
});
|
||||
}
|
||||
|
||||
tactic take(tactic const & t, unsigned k) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s) -> proof_state_seq {
|
||||
proof_state s = _s.update_report_failure(false);
|
||||
return take(k, t(env, ios, s));
|
||||
});
|
||||
}
|
||||
|
||||
tactic discard(tactic const & t, unsigned k) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & _s) -> proof_state_seq {
|
||||
proof_state s = _s.update_report_failure(false);
|
||||
auto r = t(env, ios, s);
|
||||
for (unsigned i = 0; i < k; i++) {
|
||||
auto m = r.pull();
|
||||
if (!m)
|
||||
return proof_state_seq();
|
||||
r = m->second;
|
||||
}
|
||||
return r;
|
||||
});
|
||||
}
|
||||
|
||||
tactic beta_tactic() {
|
||||
return tactic01([=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
||||
bool reduced = false;
|
||||
goals new_gs = map_goals(s, [&](goal const & g) -> optional<goal> {
|
||||
expr new_meta = beta_reduce(g.get_meta());
|
||||
expr new_type = beta_reduce(g.get_type());
|
||||
if (new_meta != g.get_meta() || new_type != g.get_type())
|
||||
reduced = true;
|
||||
return some(goal(new_meta, new_type));
|
||||
});
|
||||
return reduced ? some(proof_state(s, new_gs)) : none_proof_state();
|
||||
});
|
||||
}
|
||||
|
||||
proof_state_seq focus_core(tactic const & t, unsigned i, environment const & env, io_state const & ios, proof_state const & s) {
|
||||
goals gs = s.get_goals();
|
||||
if (i >= length(gs))
|
||||
return proof_state_seq();
|
||||
goal const & g = get_ith(gs, i);
|
||||
proof_state new_s(s, goals(g)); // singleton goal
|
||||
return map(t(env, ios, new_s), [=](proof_state const & s2) {
|
||||
// we have to put back the goals that were not selected
|
||||
buffer<goal> tmp;
|
||||
to_buffer(gs, tmp);
|
||||
buffer<goal> new_gs;
|
||||
new_gs.append(i, tmp.data());
|
||||
for (auto g : s2.get_goals())
|
||||
new_gs.push_back(g);
|
||||
new_gs.append(tmp.size()-i-1, tmp.data()+i+1);
|
||||
return proof_state(s2, to_list(new_gs.begin(), new_gs.end()));
|
||||
});
|
||||
}
|
||||
|
||||
tactic focus(tactic const & t, unsigned i) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
||||
return focus_core(t, i, env, ios, s);
|
||||
});
|
||||
}
|
||||
|
||||
tactic all_goals(tactic const & t) {
|
||||
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
||||
tactic r = id_tactic();
|
||||
unsigned i = length(s.get_goals());
|
||||
while (i > 0) {
|
||||
--i;
|
||||
r = then(r, focus(t, i));
|
||||
}
|
||||
return r(env, ios, s);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
|
||||
Author: Leonardo de Moura
|
||||
*/
|
||||
#pragma once
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include "util/lazy_list.h"
|
||||
#include "library/io_state.h"
|
||||
#include "library/generic_exception.h"
|
||||
#include "library/tactic/proof_state.h"
|
||||
|
||||
namespace lean {
|
||||
/** \brief Throw an exception is \c v contains local constants, \c e is only used for position information. */
|
||||
void check_has_no_local(expr const & v, expr const & e, char const * tac_name);
|
||||
|
||||
class tactic_exception : public generic_exception {
|
||||
optional<proof_state> m_ps;
|
||||
public:
|
||||
tactic_exception(char const * msg, optional<expr> const & m, pp_fn const & fn);
|
||||
tactic_exception(char const * msg, optional<expr> const & m, proof_state const & ps, pp_fn const & fn);
|
||||
tactic_exception(expr const & e, std::string const & msg);
|
||||
tactic_exception(expr const & e, char const * msg);
|
||||
tactic_exception(expr const & e, sstream const & strm);
|
||||
tactic_exception(expr const & e, pp_fn const & fn);
|
||||
tactic_exception(std::string const & msg);
|
||||
tactic_exception(char const * msg);
|
||||
tactic_exception(sstream const & strm);
|
||||
tactic_exception(pp_fn const & fn);
|
||||
optional<proof_state> const & get_proof_state() const { return m_ps; }
|
||||
};
|
||||
|
||||
#define throw_tactic_exception_if_enabled(ps, msg) if (ps.report_failure()) throw tactic_exception(msg);
|
||||
void throw_no_goal_if_enabled(proof_state const & ps);
|
||||
|
||||
typedef lazy_list<proof_state> proof_state_seq;
|
||||
|
||||
typedef std::function<proof_state_seq(environment const &, io_state const &, proof_state const &)> tactic;
|
||||
|
||||
inline optional<tactic> none_tactic() { return optional<tactic>(); }
|
||||
inline optional<tactic> some_tactic(tactic const & t) { return optional<tactic>(t); }
|
||||
inline optional<tactic> some_tactic(tactic && t) { return optional<tactic>(std::forward<tactic>(t)); }
|
||||
|
||||
template<typename F> inline proof_state_seq mk_proof_state_seq(F && f) { return mk_lazy_list<proof_state>(std::forward<F>(f)); }
|
||||
|
||||
tactic tactic01(std::function<optional<proof_state>(environment const &, io_state const & ios, proof_state const &)> f);
|
||||
tactic tactic1(std::function<proof_state(environment const &, io_state const & ios, proof_state const &)> f);
|
||||
|
||||
/** \brief Return a "do nothing" tactic (aka skip). */
|
||||
tactic id_tactic();
|
||||
/** \brief Return a tactic the always fails. */
|
||||
tactic fail_tactic();
|
||||
/** \brief Return a tactic that fails if there are unsolved goals. */
|
||||
tactic now_tactic();
|
||||
/** \brief Return a tactic that performs \c t1 followed by \c t2. */
|
||||
tactic then(tactic const & t1, tactic const & t2);
|
||||
inline tactic operator<<(tactic const & t1, tactic const & t2) { return then(t1, t2); }
|
||||
/** \brief Return a tactic that applies \c t1, and if \c t1 returns the empty sequence of states, then applies \c t2. */
|
||||
tactic orelse(tactic const & t1, tactic const & t2);
|
||||
inline tactic operator||(tactic const & t1, tactic const & t2) { return orelse(t1, t2); }
|
||||
inline tactic try_tactic(tactic const & t) { return orelse(t, id_tactic()); }
|
||||
/** \brief Return a tactic that appies \c t, but using the additional set of options \c opts. */
|
||||
tactic using_params(tactic const & t, options const & opts);
|
||||
/**
|
||||
\brief Return a tactic that tries the tactic \c t for at most \c ms milliseconds.
|
||||
If the tactic does not terminate in \c ms milliseconds, then the empty
|
||||
sequence is returned.
|
||||
|
||||
\remark the tactic \c t is executed in a separate execution thread.
|
||||
|
||||
\remark \c check_ms is how often the main thread checks whether the child
|
||||
thread finished.
|
||||
*/
|
||||
tactic try_for(tactic const & t, unsigned ms, unsigned check_ms = 1);
|
||||
|
||||
/** \brief Return a tactic that rotate goals to the left n steps */
|
||||
tactic rotate_left(unsigned n);
|
||||
/** \brief Return a tactic that rotate goals to the right n steps */
|
||||
tactic rotate_right(unsigned n);
|
||||
|
||||
/**
|
||||
\brief Return a tactic that executes \c t1 and \c t2 in parallel.
|
||||
This is similar to \c append and \c interleave. The order of
|
||||
the elements in the output sequence is not deterministic.
|
||||
It depends on how fast \c t1 and \c t2 produce their output.
|
||||
|
||||
\remark \c check_ms is how often the main thread checks whether the children
|
||||
threads finished.
|
||||
*/
|
||||
tactic par(tactic const & t1, tactic const & t2, unsigned check_ms);
|
||||
inline tactic par(tactic const & t1, tactic const & t2) { return par(t1, t2, 1); }
|
||||
/**
|
||||
\brief Return a tactic that keeps applying \c t until it fails.
|
||||
*/
|
||||
tactic repeat(tactic const & t);
|
||||
/**
|
||||
\brief Similar to \c repeat, but execute \c t at most \c k times.
|
||||
|
||||
\remark The value \c k is the depth of the recursion.
|
||||
For example, if tactic \c t always produce a sequence of size 2,
|
||||
then tactic \c t will be applied 2^k times.
|
||||
*/
|
||||
tactic repeat_at_most(tactic const & t, unsigned k);
|
||||
/**
|
||||
\brief Return a tactic that applies \c t, but takes at most \c
|
||||
\c k elements from the sequence produced by \c t.
|
||||
*/
|
||||
tactic take(tactic const & t, unsigned k);
|
||||
/**
|
||||
\brief Return a tactic that applies \c t, but discards the first
|
||||
\c k elements from the sequence produced by \c t.
|
||||
*/
|
||||
tactic discard(tactic const & t, unsigned k);
|
||||
|
||||
/** \brief Return a tactic that renames hypothesis \c from into \c to in the current goal. */
|
||||
tactic rename_tactic(name const & from, name const & to);
|
||||
|
||||
typedef std::function<bool(environment const & env, io_state const & ios, proof_state const & s)> proof_state_pred; // NOLINT
|
||||
/**
|
||||
\brief Return a tactic that applies the predicate \c p to the input state.
|
||||
If \c p returns true, then applies \c t1. Otherwise, applies \c t2.
|
||||
*/
|
||||
tactic cond(proof_state_pred p, tactic const & t1, tactic const & t2);
|
||||
/** \brief Syntax-sugar for cond(p, t, id_tactic()) */
|
||||
inline tactic when(proof_state_pred p, tactic const & t) { return cond(p, t, id_tactic()); }
|
||||
/**
|
||||
\brief Return a tactic that applies \c t only to the i-th goal.
|
||||
The tactic fails if the input state does have at least i goals.
|
||||
*/
|
||||
tactic focus(tactic const & t, unsigned i);
|
||||
inline tactic focus(tactic const & t) { return focus(t, 0); }
|
||||
/** \brief Return a tactic that applies beta-reduction. */
|
||||
tactic beta_tactic();
|
||||
/** \brief Apply \c t to all goals in the proof state */
|
||||
tactic all_goals(tactic const & t);
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue