(* Wrap over cancelR to simplify equations of the form
      dyn d1 = dyn d2       (1)
   into
          d1 = d2           (2)
   if d1 and d2 has both the same type A.

   The idea is simple: search in the output of cancelR expressions like (1)
   and output the equation (2). The rest of the propositions are outputted
   as they are. The output of cancelR has the shape
      p1 /\ ... /\ pn
   so we only care about the /\.

   The final automated lemma, cancelRR, use another nice pattern to trigger
   the canonical structure inference mechanism. It works by equating a
   proposition p with itself, so we can have the output of cancelR in one
   side, the projector of the structure on the other side, and make them
   match with a singleton object that just match them.
*)

Structure tagged_prop := Tag {puntag :> Prop}.(* Wrap over cancelR to simplify equations of the form
      dyn d1 = dyn d2       (1)
   into
          d1 = d2           (2)
   if d1 and d2 has both the same type A.

   The idea is simple: search in the output of cancelR expressions like (1)
   and output the equation (2). The rest of the propositions are outputted
   as they are. The output of cancelR has the shape
      p1 /\ ... /\ pn
   so we only care about the /\.

   The final automated lemma, cancelRR, use another nice pattern to trigger
   the canonical structure inference mechanism. It works by equating a
   proposition p with itself, so we can have the output of cancelR in one
   side, the projector of the structure on the other side, and make them
   match with a singleton object that just match them.
*)

Structure tagged_prop := Tag {puntag :> Prop}.(* Wrap over cancelR to simplify equations of the form
      dyn d1 = dyn d2       (1)
   into
          d1 = d2           (2)
   if d1 and d2 has both the same type A.

   The idea is simple: search in the output of cancelR expressions like (1)
   and output the equation (2). The rest of the propositions are outputted
   as they are. The output of cancelR has the shape
      p1 /\ ... /\ pn
   so we only care about the /\.

   The final automated lemma, cancelRR, use another nice pattern to trigger
   the canonical structure inference mechanism. It works by equating a
   proposition p with itself, so we can have the output of cancelR in one
   side, the projector of the structure on the other side, and make them
   match with a singleton object that just match them.
*)

Structure tagged_prop := Tag {puntag :> Prop}.Definition default_tag := Tag.Definition dyneq_tag := default_tag.Canonical Structure and_tag p := dyneq_tag p.Structure form (p : Prop) :=
  Form {prop_of :> tagged_prop;
        _ : p <-> puntag prop_of}.Structure form (p : Prop) :=
  Form {prop_of :> tagged_prop;
        _ : p <-> puntag prop_of}.Structure form (p : Prop) :=
  Form {prop_of :> tagged_prop;
        _ : p <-> puntag prop_of}.Program
Canonical Structure
  conj_struct p1 p2 (f1 : form p1) (f2 : form p2) :=
  @Form (p1 /\ p2) (and_tag (f1 /\ f2)) _.Program
Canonical Structure
  dyneq_struct A (v1 v2 : A) :=
  @Form (v1 = v2) (dyneq_tag (dyn v1 = dyn v2)) _.Program
Canonical Structure
  default_struct p :=
   @Form p (default_tag p) _.

Lemma simplify p (g : form p) : puntag (prop_of g) -> p.