(************************************************************************) (* v * The Coq Proof Assistant / The Coq Development Team *) (* c | _ -> failwith "tauto: anomaly" let is_empty ist = if is_empty_type (assoc_last ist) then <:tactic> else <:tactic> let is_unit ist = if is_unit_type (assoc_last ist) then <:tactic> else <:tactic> let is_conj ist = let ind = assoc_last ist in if (is_conjunction ind) && (is_nodep_ind ind) then <:tactic> else <:tactic> let is_disj ist = if is_disjunction (assoc_last ist) then <:tactic> else <:tactic> let not_dep_intros ist = <:tactic< repeat match goal with | |- (?X1 -> ?X2) => intro | |- (Coq.Init.Logic.iff _ _) => unfold Coq.Init.Logic.iff | |- (Coq.Init.Logic.not _) => unfold Coq.Init.Logic.not | H:(Coq.Init.Logic.iff _ _)|- _ => unfold Coq.Init.Logic.iff in H | H:(Coq.Init.Logic.not _)|-_ => unfold Coq.Init.Logic.not in H | H:(Coq.Init.Logic.iff _ _)->_|- _ => unfold Coq.Init.Logic.iff in H | H:(Coq.Init.Logic.not _)->_|-_ => unfold Coq.Init.Logic.not in H end >> let axioms ist = let t_is_unit = tacticIn is_unit and t_is_empty = tacticIn is_empty in <:tactic< match reverse goal with | |- ?X1 => $t_is_unit; constructor 1 | _:?X1 |- _ => $t_is_empty; elimtype X1; assumption | _:?X1 |- ?X1 => assumption end >> let simplif ist = let t_is_unit = tacticIn is_unit and t_is_conj = tacticIn is_conj and t_is_disj = tacticIn is_disj and t_not_dep_intros = tacticIn not_dep_intros in <:tactic< $t_not_dep_intros; repeat (match reverse goal with | id: (?X1 _ _) |- _ => $t_is_conj; elim id; do 2 intro; clear id | id: (?X1 _ _) |- _ => $t_is_disj; elim id; intro; clear id | id0: ?X1-> ?X2, id1: ?X1|- _ => (* generalize (id0 id1); intro; clear id0 does not work (see Marco Maggiesi's bug PR#301) so we instead use Assert and exact. *) assert X2; [exact (id0 id1) | clear id0] | id: ?X1 -> ?X2|- _ => $t_is_unit; cut X2; [ intro; clear id | (* id : ?X1 -> ?X2 |- ?X2 *) cut X1; [exact id| constructor 1; fail] ] | id: (?X1 ?X2 ?X3) -> ?X4|- _ => $t_is_conj; cut (X2-> X3-> X4); [ intro; clear id | (* id: (?X1 ?X2 ?X3) -> ?X4 |- ?X2 -> ?X3 -> ?X4 *) intro; intro; cut (X1 X2 X3); [exact id| split; assumption] ] | id: (?X1 ?X2 ?X3) -> ?X4|- _ => $t_is_disj; cut (X3-> X4); [cut (X2-> X4); [intro; intro; clear id | (* id: (?X1 ?X2 ?X3) -> ?X4 |- ?X2 -> ?X4 *) intro; cut (X1 X2 X3); [exact id| left; assumption] ] | (* id: (?X1 ?X2 ?X3) -> ?X4 |- ?X3 -> ?X4 *) intro; cut (X1 X2 X3); [exact id| right; assumption] ] | |- (?X1 _ _) => $t_is_conj; split end; $t_not_dep_intros) >> let rec tauto_intuit t_reduce solver ist = let t_axioms = tacticIn axioms and t_simplif = tacticIn simplif and t_is_disj = tacticIn is_disj and t_tauto_intuit = tacticIn (tauto_intuit t_reduce solver) in let t_solver = Tacexpr.TacArg (valueIn (VTactic (dummy_loc,solver))) in <:tactic< ($t_simplif;$t_axioms || match reverse goal with | id:(?X1-> ?X2)-> ?X3|- _ => cut X3; [ intro; clear id; $t_tauto_intuit | cut (X1 -> X2); [ exact id | generalize (fun y:X2 => id (fun x:X1 => y)); intro; clear id; solve [ $t_tauto_intuit ]]] | |- (?X1 _ _) => $t_is_disj; solve [left;$t_tauto_intuit | right;$t_tauto_intuit] end || (* NB: [|- _ -> _] matches any product *) match goal with | |- _ -> _ => intro; $t_tauto_intuit | |- _ => $t_reduce;$t_solver end || $t_solver ) >> let reduction_not_iff=interp <:tactic progress unfold Coq.Init.Logic.not, Coq.Init.Logic.iff | H:_ |- _ => progress unfold Coq.Init.Logic.not, Coq.Init.Logic.iff in H end >> let t_reduction_not_iff = Tacexpr.TacArg (valueIn (VTactic (dummy_loc,reduction_not_iff))) let intuition_gen tac = interp (tacticIn (tauto_intuit t_reduction_not_iff tac)) let simplif_gen = interp (tacticIn simplif) let tauto g = try intuition_gen (interp <:tactic>) g with Refiner.FailError _ | UserError _ -> errorlabstrm "tauto" [< str "tauto failed" >] let default_intuition_tac = interp <:tactic< auto with * >> TACTIC EXTEND tauto | [ "tauto" ] -> [ tauto ] END TACTIC EXTEND intuition | [ "intuition" ] -> [ intuition_gen default_intuition_tac ] | [ "intuition" tactic(t) ] -> [ intuition_gen (snd t) ] END