Ltac2Tutorial.tutorial1
From Ltac2 Require Import Ltac2.
From Coq Require Import List.
(* This file shows how to do proof by reflection with Ltac2, *)
(* See http://adam.chlipala.net/cpdt/html/Cpdt.Reflection.html for a more detailed explanation of the high-level idea *)
Module Type Monoid.
(* Carrier *)
Parameter M : Type.
(* Neutral element *)
Parameter mzero : M.
(* Binary operator *)
Parameter madd : M -> M -> M.
(* Axioms *)
Axiom madd_assoc : forall a b c, madd (madd a b) c = madd a (madd b c).
Axiom madd_idl : forall a, madd mzero a = a.
Axiom madd_idr : forall a, madd a mzero = a.
End Monoid.
Module MonoidSimp (M : Monoid).
Import M.
Inductive mexp : Type :=
| Id : mexp
| Var : M -> mexp
| Op : mexp -> mexp -> mexp.
Fixpoint denote_mexp (e : mexp) :=
match e with
| Id => mzero
| Var a => a
| Op a b => madd (denote_mexp a) (denote_mexp b)
end.
Definition denote_mexps :=
fold_right madd mzero.
Fixpoint flatten (e : mexp) :=
match e with
| Id => nil
| Var a => cons a nil
| Op e0 e1 => flatten e0 ++ flatten e1
end.
Lemma denote_append L1 L2 :
denote_mexps (L1 ++ L2) = madd (denote_mexps L1) (denote_mexps L2).
Proof.
revert L2.
induction L1 as [|m L1 ihL1].
- simpl. intros L2.
rewrite madd_idl.
reflexivity.
- intros L2. simpl.
rewrite ihL1.
rewrite madd_assoc.
reflexivity.
Qed.
Lemma flatten_correct (e : mexp) :
denote_mexp e = denote_mexps (flatten e).
Proof.
induction e; simpl.
- reflexivity.
- rewrite madd_idr. reflexivity.
- rewrite denote_append.
rewrite IHe1.
rewrite IHe2.
reflexivity.
Qed.
(* To show that two expressions are equal, it suffices to show that their simplified versions are equal *)
Lemma monoid_reflect (e0 e1 : mexp) :
denote_mexps (flatten e0) = denote_mexps (flatten e1) ->
denote_mexp e0 = denote_mexp e1.
Proof.
do 2 (rewrite flatten_correct).
apply id.
Qed.
(* Convert a Gallina expression as a term of the type mexp *)
Ltac2 rec reify a :=
lazy_match! a with
| mzero => 'Id
| madd ?a ?b =>
let e0 := reify a in
let e1 := reify b in
'(Op $e0 $e1)
| _ => '(Var $a)
end.
(* Apply monoid_reflect and simplify the result for a goal of the
form a = b where a and b are both of type M *)
Ltac2 rec monoid_simp () :=
lazy_match! goal with
| [ |- ?a = ?b] =>
let m0 := reify a in
let m1 := reify b in
apply (monoid_reflect $m0 $m1)
| [ |- _] => Control.backtrack_tactic_failure "Wrong goal type"
end.
End MonoidSimp.
(* Let's try out the simplifier *)
Module MonoidSimpTest (Import A : Monoid).
Module AS := MonoidSimp A.
Import AS.
Example test0 : forall (a b c d : M),
madd a (madd (madd b c) d) = madd (madd a b) (madd c d).
Proof.
intros a b c d. monoid_simp(). simpl. reflexivity.
Qed.
End MonoidSimpTest.
From Coq Require Import List.
(* This file shows how to do proof by reflection with Ltac2, *)
(* See http://adam.chlipala.net/cpdt/html/Cpdt.Reflection.html for a more detailed explanation of the high-level idea *)
Module Type Monoid.
(* Carrier *)
Parameter M : Type.
(* Neutral element *)
Parameter mzero : M.
(* Binary operator *)
Parameter madd : M -> M -> M.
(* Axioms *)
Axiom madd_assoc : forall a b c, madd (madd a b) c = madd a (madd b c).
Axiom madd_idl : forall a, madd mzero a = a.
Axiom madd_idr : forall a, madd a mzero = a.
End Monoid.
Module MonoidSimp (M : Monoid).
Import M.
Inductive mexp : Type :=
| Id : mexp
| Var : M -> mexp
| Op : mexp -> mexp -> mexp.
Fixpoint denote_mexp (e : mexp) :=
match e with
| Id => mzero
| Var a => a
| Op a b => madd (denote_mexp a) (denote_mexp b)
end.
Definition denote_mexps :=
fold_right madd mzero.
Fixpoint flatten (e : mexp) :=
match e with
| Id => nil
| Var a => cons a nil
| Op e0 e1 => flatten e0 ++ flatten e1
end.
Lemma denote_append L1 L2 :
denote_mexps (L1 ++ L2) = madd (denote_mexps L1) (denote_mexps L2).
Proof.
revert L2.
induction L1 as [|m L1 ihL1].
- simpl. intros L2.
rewrite madd_idl.
reflexivity.
- intros L2. simpl.
rewrite ihL1.
rewrite madd_assoc.
reflexivity.
Qed.
Lemma flatten_correct (e : mexp) :
denote_mexp e = denote_mexps (flatten e).
Proof.
induction e; simpl.
- reflexivity.
- rewrite madd_idr. reflexivity.
- rewrite denote_append.
rewrite IHe1.
rewrite IHe2.
reflexivity.
Qed.
(* To show that two expressions are equal, it suffices to show that their simplified versions are equal *)
Lemma monoid_reflect (e0 e1 : mexp) :
denote_mexps (flatten e0) = denote_mexps (flatten e1) ->
denote_mexp e0 = denote_mexp e1.
Proof.
do 2 (rewrite flatten_correct).
apply id.
Qed.
(* Convert a Gallina expression as a term of the type mexp *)
Ltac2 rec reify a :=
lazy_match! a with
| mzero => 'Id
| madd ?a ?b =>
let e0 := reify a in
let e1 := reify b in
'(Op $e0 $e1)
| _ => '(Var $a)
end.
(* Apply monoid_reflect and simplify the result for a goal of the
form a = b where a and b are both of type M *)
Ltac2 rec monoid_simp () :=
lazy_match! goal with
| [ |- ?a = ?b] =>
let m0 := reify a in
let m1 := reify b in
apply (monoid_reflect $m0 $m1)
| [ |- _] => Control.backtrack_tactic_failure "Wrong goal type"
end.
End MonoidSimp.
(* Let's try out the simplifier *)
Module MonoidSimpTest (Import A : Monoid).
Module AS := MonoidSimp A.
Import AS.
Example test0 : forall (a b c d : M),
madd a (madd (madd b c) d) = madd (madd a b) (madd c d).
Proof.
intros a b c d. monoid_simp(). simpl. reflexivity.
Qed.
End MonoidSimpTest.