While there is no built-in tactic or combinator, you can implement it yourself as follows:
ML {* fun solved_tac thm = if nprems_of thm = 0 then Seq.single thm else Seq.empty *} method_setup solved = {* Scan.succeed (K (SIMPLE_METHOD solved_tac)) *}
This creates a new solved method, which will be successful if the current goal is completely resolved or will fail if one or more subgoals remain.
It can be used, for example, as follows:
lemma "a ∨ ¬ a " apply ((rule disjI1, solved) | (simp, solved)) done
Without the solved Isabelle will choose the rule disjI1 side of the apply step, leaving you with an unsolvable target. With a solved on each side, Isabelle tries to use rule disjI1 and, when he cannot solve the goal, switches to simp , which is then successfully executed.
This can be used to solve individual goals using the syntax Isabelle (...)[1] . For example, the following statement will try to solve as many simp as possible using simp , but leave the subgoal unchanged if simp cannot completely solve it:
apply ((simp, solved)[1])+
source share