Library Mtac2.ideas.SubgoalsStrict
From Mtac2 Require Import Base Tactics Datatypes List Sorts.
Import Sorts.S.
Import ListNotations.
Set Implicit Arguments.
Import ProdNotations.
Require Import Strings.String.
Set Universe Polymorphism.
Import Sorts.S.
Import ListNotations.
Set Implicit Arguments.
Import ProdNotations.
Require Import Strings.String.
Set Universe Polymorphism.
This is a simple example tighting up a bit the types of tactics in order to
ensure a property. In this case, we make sure that a variation of `apply`
is composed with as many tactics as the number required by the number of
hypotheses of the type.
We won't statically check that the tactic isn't cheating. If the tactic
produce a different number of subgoals, that is not our problem here.
For that reason, we use the following record instead of a Vector.t: we want
to easily embed tactics into ntactics and back.
Record PackedVec (A: Type) (count: nat) := mkPackedVec {
goals : mlist (A *m goal gs_any)
}.
Definition ntactic A n := goal gs_open -> M (PackedVec A n).
Import M.
Import M.notations.
Coercion n_to_g A n (nt : ntactic A n) : gtactic A := fun g=>pv <- nt g; M.ret pv.(goals).
goals : mlist (A *m goal gs_any)
}.
Definition ntactic A n := goal gs_open -> M (PackedVec A n).
Import M.
Import M.notations.
Coercion n_to_g A n (nt : ntactic A n) : gtactic A := fun g=>pv <- nt g; M.ret pv.(goals).
For the composition, we can't be generic here: we produce a gtactic out of
the composition of an ntactic with nth gtactics.
Class NSeq (A B : Type) n (nt: ntactic A n) (l: mlist (gtactic B)) (pf: mlength l = n) :=
nseq : gtactic B.
Arguments nseq {A B _} _%tactic _%tactic _ {_}.
Import Mtac2.lib.List.
Instance nseq_list {A B} n (nt: ntactic A n) (l: mlist (gtactic B)) pf: NSeq nt l pf := fun g =>
gs <- nt g;
ls <- T.gmap l gs.(goals);
let res := dreduce (@mconcat, @mapp) (mconcat ls) in
T.filter_goals res.
Notation "t1 '&n>' ts" :=
(nseq t1 ts eq_refl) (at level 41, left associativity) : tactic_scope.
Import Datatypes.
nseq : gtactic B.
Arguments nseq {A B _} _%tactic _%tactic _ {_}.
Import Mtac2.lib.List.
Instance nseq_list {A B} n (nt: ntactic A n) (l: mlist (gtactic B)) pf: NSeq nt l pf := fun g =>
gs <- nt g;
ls <- T.gmap l gs.(goals);
let res := dreduce (@mconcat, @mapp) (mconcat ls) in
T.filter_goals res.
Notation "t1 '&n>' ts" :=
(nseq t1 ts eq_refl) (at level 41, left associativity) : tactic_scope.
Import Datatypes.
max_apply t applies theorem t to the current goal.
It generates a subgoal for each non-dependent hypothesis in the theorem.
Definition max_apply {T} (c : T) : tactic := fun g=>
match g with @Metavar SType gT eg =>
(mfix1 go (d : dyn) : M (mlist (unit *m goal _)) :=
mmatch d return M (mlist (unit *m goal _)) with
| [? T1 T2 f] @Dyn (T1 -> T2) f =>
e <- M.evar T1;
r <- go (Dyn (f e));
M.ret ((m: tt, AnyMetavar SType e) :m: r)
| [? T1 T2 f] @Dyn (forall x:T1, T2 x) f =>
e <- M.evar T1;
r <- go (Dyn (f e));
M.ret r
| Dyn eg =u> M.ret [m:]
| _ =>
dcase d as ty, el in
M.raise (T.CantApply ty gT)
end) (Dyn c)
| @Metavar SProp _ _ => M.failwith "It's a prop!"
end.
Definition count_nondep_binders (T: Type) : M nat :=
(mfix1 go (T : Type) : M nat :=
mmatch T return M nat with
| [? T1 T2] (T1 -> T2) =>
r <- go T2;
M.ret (S r)
| [? T1 T2] (forall x:T1, T2 x) =>
nu (FreshFromStr "name") mNone (fun e:T1=>go (T2 e))
| _ => M.ret 0
end) T.
Definition napply {T} {e: runner (count_nondep_binders T)} (c : T) : ntactic unit (@eval _ _ e) := fun g=>
ls <- max_apply c g;
M.ret (mkPackedVec (@eval _ _ e) ls).
Import TacticsBase.T.
Import TacticsBase.T.notations.
match g with @Metavar SType gT eg =>
(mfix1 go (d : dyn) : M (mlist (unit *m goal _)) :=
mmatch d return M (mlist (unit *m goal _)) with
| [? T1 T2 f] @Dyn (T1 -> T2) f =>
e <- M.evar T1;
r <- go (Dyn (f e));
M.ret ((m: tt, AnyMetavar SType e) :m: r)
| [? T1 T2 f] @Dyn (forall x:T1, T2 x) f =>
e <- M.evar T1;
r <- go (Dyn (f e));
M.ret r
| Dyn eg =u> M.ret [m:]
| _ =>
dcase d as ty, el in
M.raise (T.CantApply ty gT)
end) (Dyn c)
| @Metavar SProp _ _ => M.failwith "It's a prop!"
end.
Definition count_nondep_binders (T: Type) : M nat :=
(mfix1 go (T : Type) : M nat :=
mmatch T return M nat with
| [? T1 T2] (T1 -> T2) =>
r <- go T2;
M.ret (S r)
| [? T1 T2] (forall x:T1, T2 x) =>
nu (FreshFromStr "name") mNone (fun e:T1=>go (T2 e))
| _ => M.ret 0
end) T.
Definition napply {T} {e: runner (count_nondep_binders T)} (c : T) : ntactic unit (@eval _ _ e) := fun g=>
ls <- max_apply c g;
M.ret (mkPackedVec (@eval _ _ e) ls).
Import TacticsBase.T.
Import TacticsBase.T.notations.