diff --git a/src/library/tactic/tactic.cpp b/src/library/tactic/tactic.cpp index 94bec1bb4..3a2237d9c 100644 --- a/src/library/tactic/tactic.cpp +++ b/src/library/tactic/tactic.cpp @@ -213,4 +213,38 @@ tactic par(tactic t1, tactic t2, unsigned check_ms) { } }); } + +tactic repeat(tactic t) { + return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq { + tactic t1(t); + proof_state_seq r = t1(env, io, s1); + if (!r) { + return proof_state_seq(s1); + } else { + return map_append(r, [=](proof_state const & s2) { + check_interrupted(); + tactic t2 = repeat(t1); + return t2(env, io, s2); + }); + } + }); +} + +tactic repeat_at_most(tactic t, unsigned k) { + return mk_tactic([=](environment const & env, io_state const & io, proof_state const & s1) -> proof_state_seq { + if (k == 0) + return proof_state_seq(s1); + tactic t1(t); + proof_state_seq r = t1(env, io, s1); + if (!r) { + return proof_state_seq(s1); + } else { + return map_append(r, [=](proof_state const & s2) { + check_interrupted(); + tactic t2 = repeat_at_most(t1, k - 1); + return t2(env, io, s2); + }); + } + }); +} } diff --git a/src/library/tactic/tactic.h b/src/library/tactic/tactic.h index 9d574b97d..df5eb14d5 100644 --- a/src/library/tactic/tactic.h +++ b/src/library/tactic/tactic.h @@ -120,6 +120,16 @@ tactic interleave(tactic t1, tactic t2); threads finished. */ tactic par(tactic t1, tactic t2, unsigned check_ms = 1); +/** + \brief Return a tactic that keeps applying \c t until it fails. +*/ +tactic repeat(tactic t); +/** + \brief Similar to \c repeat, but execute \c t at most \c k times. -tactic repeat(tactic t1); + \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 t, unsigned k); } diff --git a/src/tests/library/tactic/tactic.cpp b/src/tests/library/tactic/tactic.cpp index 9d0e27bff..444909417 100644 --- a/src/tests/library/tactic/tactic.cpp +++ b/src/tests/library/tactic/tactic.cpp @@ -66,6 +66,7 @@ static void tst1() { std::cout << "proof 2: " << t.solve(env, io, ctx, q) << "\n"; check_failure(now_tactic(), env, io, ctx, q); std::cout << "proof 2: " << orelse(fail_tactic(), t).solve(env, io, ctx, q) << "\n"; + #ifndef __APPLE__ check_failure(try_for(loop_tactic(), 100), env, io, ctx, q); std::cout << "proof 1: " << try_for(t, 10000).solve(env, io, s) << "\n"; @@ -85,6 +86,11 @@ static void tst1() { lean_assert(flag1); std::cout << "proof 2: " << par(loop_tactic(), par(loop_tactic(), t)).solve(env, io, ctx, q) << "\n"; #endif + + std::cout << "proof 2: " << orelse(then(repeat_at_most(append(msg_tactic("hello1"), msg_tactic("hello2")), 5), fail_tactic()), + t).solve(env, io, ctx, q) << "\n"; + + std::cout << "done\n"; }