feat(library/tactic): add rotate_left/rotate_right tactics, closes #278
This commit is contained in:
parent
8e9f97e95e
commit
9547e2d077
7 changed files with 74 additions and 1 deletions
|
@ -38,6 +38,9 @@ opaque definition id : tactic := builtin
|
|||
opaque definition beta : tactic := builtin
|
||||
opaque definition info : tactic := builtin
|
||||
opaque definition whnf : tactic := builtin
|
||||
opaque definition rotate_left (k : num) := builtin
|
||||
opaque definition rotate_right (k : num) := builtin
|
||||
definition rotate (k : num) := rotate_left k
|
||||
|
||||
-- This is just a trick to embed expressions into tactics.
|
||||
-- The nested expressions are "raw". They tactic should
|
||||
|
|
|
@ -119,7 +119,7 @@
|
|||
;; tactics
|
||||
(,(rx (not (any "\.")) word-start
|
||||
(or "\\b.*_tac" "Cond" "or_else" "then" "try" "when" "assumption" "eassumption" "rapply" "apply" "rename" "intro" "intros"
|
||||
"generalize" "back" "beta" "done" "exact" "repeat" "whnf")
|
||||
"generalize" "back" "beta" "done" "exact" "repeat" "whnf" "rotate" "rotate_left" "rotate_right")
|
||||
word-end)
|
||||
. 'font-lock-constant-face)
|
||||
;; Types
|
||||
|
|
|
@ -272,6 +272,25 @@ void register_unary_num_tac(name const & n, std::function<tactic(tactic const &,
|
|||
});
|
||||
}
|
||||
|
||||
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f) {
|
||||
register_tac(n, [=](type_checker & tc, elaborate_fn const &, expr const & e, pos_info_provider const * p) {
|
||||
buffer<expr> args;
|
||||
get_app_args(e, args);
|
||||
if (args.size() != 1)
|
||||
throw expr_to_tactic_exception(e, "invalid tactic, it must have one argument");
|
||||
optional<mpz> k = to_num(args[0]);
|
||||
if (!k)
|
||||
k = to_num(tc.whnf(args[0]).first);
|
||||
if (!k)
|
||||
throw expr_to_tactic_exception(e, "invalid tactic, argument must be a numeral");
|
||||
if (!k->is_unsigned_int())
|
||||
throw expr_to_tactic_exception(e,
|
||||
"invalid tactic, argument does not fit in "
|
||||
"a machine unsigned integer");
|
||||
return f(k->get_unsigned_int());
|
||||
});
|
||||
}
|
||||
|
||||
static name * g_by_name = nullptr;
|
||||
|
||||
expr mk_by(expr const & e) { return mk_annotation(*g_by_name, e); }
|
||||
|
@ -351,6 +370,9 @@ void initialize_expr_to_tactic() {
|
|||
[](tactic const & t, unsigned k) { return focus(t, k); });
|
||||
register_unary_num_tac(name(*g_tactic_name, "try_for"),
|
||||
[](tactic const & t, unsigned k) { return try_for(t, k); });
|
||||
register_num_tac(name(*g_tactic_name, "rotate_left"), [](unsigned k) { return rotate_left(k); });
|
||||
register_num_tac(name(*g_tactic_name, "rotate_right"), [](unsigned k) { return rotate_right(k); });
|
||||
|
||||
register_tac(fixpoint_name,
|
||||
[](type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
|
||||
if (!is_constant(app_fn(e)))
|
||||
|
|
|
@ -79,6 +79,7 @@ void register_simple_tac(name const & n, std::function<tactic()> f);
|
|||
void register_bin_tac(name const & n, std::function<tactic(tactic const &, tactic const &)> f);
|
||||
void register_unary_tac(name const & n, std::function<tactic(tactic const &)> f);
|
||||
void register_unary_num_tac(name const & n, std::function<tactic(tactic const &, unsigned)> f);
|
||||
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f);
|
||||
|
||||
void initialize_expr_to_tactic();
|
||||
void finalize_expr_to_tactic();
|
||||
|
|
|
@ -110,6 +110,32 @@ tactic using_params(tactic const & t, options const & opts) {
|
|||
});
|
||||
}
|
||||
|
||||
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 {
|
||||
return timeout(t(env, ios, s), ms, check_ms);
|
||||
|
|
|
@ -71,6 +71,12 @@ tactic try_for(tactic const & t, unsigned ms, unsigned check_ms = 1);
|
|||
from tactic \c t2.
|
||||
*/
|
||||
tactic append(tactic const & t1, tactic const & t2);
|
||||
|
||||
/** \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);
|
||||
|
||||
inline tactic operator+(tactic const & t1, tactic const & t2) { return append(t1, t2); }
|
||||
/**
|
||||
\brief Execute both tactics and and combines their results.
|
||||
|
|
15
tests/lean/run/beginend3.lean
Normal file
15
tests/lean/run/beginend3.lean
Normal file
|
@ -0,0 +1,15 @@
|
|||
import tools.tactic
|
||||
open tactic
|
||||
|
||||
theorem foo (A : Type) (a b c : A) : a = b → b = c → a = c ∧ c = a :=
|
||||
begin
|
||||
intros (Hab, Hbc),
|
||||
apply and.intro,
|
||||
apply eq.trans,
|
||||
rotate 2,
|
||||
apply eq.trans,
|
||||
apply (eq.symm Hbc),
|
||||
apply (eq.symm Hab),
|
||||
apply Hab,
|
||||
apply Hbc,
|
||||
end
|
Loading…
Reference in a new issue