## 10.3 Examples

### 10.3.1 About the cardinality of the natural number set

A first example which shows how to use the pattern matching over the proof contexts is the proof that natural numbers have more than two elements. The proof of such a lemma can be done as shown in table 10.4.

> 6in
> `Coq` `<``Lemma card_nat: ~(EX x:nat|(EX y:nat|(z:nat)(x=z)/\(y=z))).`
> `Coq` `<``Proof.`
> `Coq` `<``Red;Intro H.`
> `Coq` `<``Elim H;Intros a Ha.`
> `Coq` `<``Elim Ha;Intros b Hb.`
> `Coq` `<``Elim (Hb (0));Elim (Hb (1));Elim (Hb (2));Intros;`
> `Coq` `<``Match Context With`
> `Coq` `<``[_:?1=?2;_:?1=?3|-?] -``>`
> `Coq` `<``Cut ?2=?3;[Discriminate|Apply trans_equal with ?1;Auto].`
> `Coq` `<``Save.`
> Table 10.4: A proof on cardinality of natural numbers

We can notice that all the (very similar) cases coming from the three eliminations (with three distinct natural numbers) are successfully solved by a Match Context structure and, in particular, with only one pattern (use of non-linear unification).

### 10.3.2 Permutation on closed lists

Another more complex example is the problem of permutation on closed lists. The aim is to show that a closed list is a permutation of another one.
First, we define the permutation predicate as shown in table 10.5.

> 6in
> `Coq` `<``Section Sort.`
> `Coq` `<``Variable A:Set.`
> `Coq` `<```
> `Coq` `<``Inductive permut:(list A)-``>``(list A)-``>``Prop:=`
> `Coq` `<``permut_refl:(l:(list A))(permut l l)`
> `Coq` `<``|permut_cons:`
> `Coq` `<``(a:A)(l0,l1:(list A))(permut l0 l1)-``>`
> `Coq` `<``(permut (cons a l0) (cons a l1))`
> `Coq` `<``|permut_append:`
> `Coq` `<``(a:A)(l:(list A))(permut (cons a l) (l^(cons a (nil A))))`
> `Coq` `<``|permut_trans:`
> `Coq` `<``(l0,l1,l2:(list A))(permut l0 l1)-``>``(permut l1 l2)-``>`
> `Coq` `<``(permut l0 l2).`
> `Coq` `<``End Sort.`
> Table 10.5: Definition of the permutation predicate

Next, we can write naturally the tactic and the result can be seen in table 10.6. We can notice that we use two toplevel definitions PermutProve and Permut. The function to be called is PermutProve which computes the lengths of the two lists and calls Permut with the length if the two lists have the same length. Permut works as expected. If the two lists are equal, it concludes. Otherwise, if the lists have identical first elements, it applies Permut on the tail of the lists. Finally, if the lists have different first elements, it puts the first element of one of the lists (here the second one which appears in the permut predicate) at the end if that is possible, i.e., if the new first element has been at this place previously. To verify that all rotations have been done for a list, we use the length of the list as an argument for Permut and this length is decremented for each rotation down to, but not including, 1 because for a list of length n, we can make exactly n-1 rotations to generate at most n distinct lists. Here, it must be noticed that we use the natural numbers of Coq for the rotation counter. In table 10.1, we can see that it is possible to use usual natural numbers but they are only used as arguments for primitive tactics and they cannot be handled, in particular, we cannot make computations with them. So, a natural choice is to use Coq data structures so that Coq makes the computations (reductions) by Eval Compute in and we can get the terms back by Match.

> 6in
> `Coq` `<``Tactic Definition Permut n:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|-(permut ? ?1 ?1)] -``>``Apply permut_refl`
> `Coq` `<``|[|-(permut ? (cons ?1 ?2) (cons ?1 ?3))] -``>`
> `Coq` `<``Let newn=Eval Compute in (length ?2) In`
> `Coq` `<``Apply permut_cons;(Permut newn)`
> `Coq` `<``|[|-(permut ?1 (cons ?2 ?3) ?4)] -``>`
> `Coq` `<``(Match Eval Compute in n With`
> `Coq` `<``[(1)] -``>``Fail`
> `Coq` `<``|_ -``>`
> `Coq` `<``Let l0'='(?3^(cons ?2 (nil ?1))) In`
> `Coq` `<``Apply (permut_trans ?1 (cons ?2 ?3) l0' ?4);`
> `Coq` `<``[Apply permut_append|`
> `Coq` `<``Compute;(Permut '(pred n))]).`
> `Permut is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition PermutProve:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|-(permut ? ?1 ?2)] -``>`
> `Coq` `<``(Match Eval Compute in ((length ?1)=(length ?2)) With`
> `Coq` `<``[?1=?1] -``>``(Permut ?1)).`
> `PermutProve is defined`
> Table 10.6: Permutation tactic

With PermutProve, we can now prove lemmas such those shown in table 10.7.

> 6in
> `Coq` `<``Lemma permut_ex1:`
> `Coq` `<``(permut nat (cons (1) (cons (2) (cons (3) (nil nat))))`
> `Coq` `<``(cons (3) (cons (2) (cons (1) (nil nat))))).`
> `Coq` `<``Proof.`
> `Coq` `<``PermutProve.`
> `Coq` `<``Save.`
> `Coq` `<```
> `Coq` `<``Lemma permut_ex2:`
> `Coq` `<``(permut nat`
> `Coq` `<``(cons (0) (cons (1) (cons (2) (cons (3) (cons (4) (cons (5)`
> `Coq` `<``(cons (6) (cons (7) (cons (8) (cons (9) (nil nat)))))))))))`
> `Coq` `<``(cons (0) (cons (2) (cons (4) (cons (6) (cons (8) (cons (9)`
> `Coq` `<``(cons (7) (cons (5) (cons (3) (cons (1) (nil nat)))))))))))).`
> `Coq` `<``Proof.`
> `Coq` `<``PermutProve.`
> `Coq` `<``Save.`
> Table 10.7: Examples of PermutProve use

### 10.3.3 Deciding intuitionistic propositional logic

The pattern matching on proof contexts allows a complete and so a powerful backtracking when returning tactic values. An interesting application is the problem of deciding intuitionistic propositional logic. Considering the contraction-free sequent calculi LJT* of Roy Dyckhoff ([Dyc92]), it is quite natural to code such a tactic using the tactic language as shown in table 10.8. The tactic Axioms tries to conclude using usual axioms. The tactic Simplif applies all the reversible rules of Dyckhoff's system. Finally, the tactic TautoProp (the main tactic to be called) simplifies with Simplif, tries to conclude with Axioms and tries several paths using the backtracking rules (one of the four Dyckhoff's rules for the left implication to get rid of the contraction and the right or).

> 6in
> `Coq` `<``Tactic Definition Axioms:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|-True] -``>``Trivial`
> `Coq` `<``|[_:False|- ?] -``>``ElimType False;Assumption`
> `Coq` `<``|[_:?1|-?1] -``>``Auto.`
> `Axioms is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition Simplif:=`
> `Coq` `<``Repeat`
> `Coq` `<``(Intros;`
> `Coq` `<``(Match Context With`
> `Coq` `<``[id:~?|-?] -``>``Red in id`
> `Coq` `<``|[id:?/\?|-?] -``>``Elim id;Do 2 Intro;Clear id`
> `Coq` `<``|[id:?\/?|-?] -``>``Elim id;Intro;Clear id`
> `Coq` `<``|[id:?1/\?2-``>``?3|-?] -``>`
> `Coq` `<``Cut ?1-``>``?2-``>``?3;[Intro|Intros;Apply id;Split;Assumption]`
> `Coq` `<``|[id:?1\/?2-``>``?3|-?] -``>`
> `Coq` `<``Cut ?2-``>``?3;[Cut ?1-``>``?3;[Intros|`
> `Coq` `<``Intro;Apply id;Left;Assumption]|`
> `Coq` `<``Intro;Apply id;Right;Assumption]`
> `Coq` `<``|[id0:?1-``>``?2;id1:?1|-?] -``>`
> `Coq` `<``Cut ?2;[Intro;Clear id0|Apply id0;Assumption]`
> `Coq` `<``|[|-?/\?] -``>``Split`
> `Coq` `<``|[|-~?] -``>``Red)).`
> `Simplif is defined`
> `Coq` `<```
> `Coq` `<``Recursive Tactic Definition TautoProp:=`
> `Coq` `<``Simplif;`
> `Coq` `<``Axioms`
> `Coq` `<``Orelse`
> `Coq` `<``Match Context With`
> `Coq` `<``[id:(?1-``>``?2)-``>``?3|-?] -``>`
> `Coq` `<``Cut ?2-``>``?3;[Intro;Cut ?1-``>``?2;[Intro;Cut ?3;[Intro;Clear id|`
> `Coq` `<``Apply id;Assumption]|Clear id]|`
> `Coq` `<``Intro;Apply id;Intro;Assumption];TautoProp`
> `Coq` `<``|[id:~?1-``>``?2|-?]-``>`
> `Coq` `<``Cut False-``>``?2;`
> `Coq` `<``[Intro;Cut ?1-``>``False;[Intro;Cut ?2;[Intro;Clear id|`
> `Coq` `<``Apply id;Assumption]|Clear id]|`
> `Coq` `<``Intro;Apply id;Red;Intro;Assumption];TautoProp`
> `Coq` `<``|[|-?\/?] -``>`
> `Coq` `<``(Left;TautoProp) Orelse (Right;TautoProp).`
> `TautoProp is defined`
> Table 10.8: Deciding intuitionistic propositions

For example, with TautoProp, we can prove tautologies like those in table 10.9.

> 6in
> `Coq` `<``Lemma tauto_ex1:(A,B:Prop)A/\B-``>``A\/B.`
> `Coq` `<``Proof.`
> `Coq` `<``TautoProp.`
> `Coq` `<``Save.`
> `Coq` `<```
> `Coq` `<``Lemma tauto_ex2:(A,B:Prop)(~~B-``>``B)-``>``(A-``>``B)-``>``~~A-``>``B.`
> `Coq` `<``Proof.`
> `Coq` `<``TautoProp.`
> `Coq` `<``Save.`
> Table 10.9: Proofs of tautologies with TautoProp

### 10.3.4 Deciding type isomorphisms

A more tricky problem is to decide equalities between types and modulo isomorphisms. Here, we choose to use the isomorphisms of the simply typed l-calculus with Cartesian product and unit type (see, for example, [RC95]). The axioms of this l-calculus are given by table 10.10.

> 6in
> `Coq` `<``Section Iso_axioms.`
> `Coq` `<```
> `Coq` `<``Variable A,B,C:Set.`
> `Coq` `<```
> `Coq` `<``Axiom Com:(A*B)==(B*A).`
> `Coq` `<``Axiom Ass:(A*(B*C))==((A*B)*C).`
> `Coq` `<``Axiom Cur:((A*B)-``>``C)==(A-``>``B-``>``C).`
> `Coq` `<``Axiom Dis:(A-``>``(B*C))==((A-``>``B)*(A-``>``C)).`
> `Coq` `<``Axiom P_unit:(A*unit)==A.`
> `Coq` `<``Axiom AR_unit:(A-``>``unit)==unit.`
> `Coq` `<``Axiom AL_unit:(unit-``>``A)==A.`
> `Coq` `<```
> `Coq` `<``Lemma Cons:B==C-``>``(A*B)==(A*C).`
> `Coq` `<``Proof.`
> `Coq` `<``Intro Heq;Rewrite Heq;Apply refl_eqT.`
> `Coq` `<``Save.`
> `Coq` `<```
> `Coq` `<``End Iso_axioms.`
> Table 10.10: Type isomorphism axioms

The tactic to judge equalities modulo this axiomatization can be written as shown in tables 10.11 and 10.12. The algorithm is quite simple. Types are reduced using axioms that can be oriented (this done by MainSimplif). The normal forms are sequences of Cartesian products without Cartesian product in the left component. These normal forms are then compared modulo permutation of the components (this is done by CompareStruct). The main tactic to be called and realizing this algorithm is IsoProve.

> 6in
> `Coq` `<``Recursive Tactic Definition Simplif trm:=`
> `Coq` `<``Match trm With`
> `Coq` `<``[(?1*?2)*?3] -``>``Rewrite` `<``- (Ass ?1 ?2 ?3);Try MainSimplif`
> `Coq` `<``|[(?1*?2)-``>``?3] -``>``Rewrite (Cur ?1 ?2 ?3);Try MainSimplif`
> `Coq` `<``|[?1-``>``(?2*?3)] -``>``Rewrite (Dis ?1 ?2 ?3);Try MainSimplif`
> `Coq` `<``|[?1*unit] -``>``Rewrite (P_unit ?1);Try MainSimplif`
> `Coq` `<``|[unit*?1] -``>``Rewrite (Com unit ?1);Try MainSimplif`
> `Coq` `<``|[?1-``>``unit] -``>``Rewrite (AR_unit ?1);Try MainSimplif`
> `Coq` `<``|[unit-``>``?1] -``>``Rewrite (AL_unit ?1);Try MainSimplif`
> `Coq` `<``|[?1*?2] -``>`
> `Coq` `<``((Simplif ?1);Try MainSimplif) Orelse`
> `Coq` `<``((Simplif ?2);Try MainSimplif)`
> `Coq` `<``|[?1-``>``?2] -``>`
> `Coq` `<``((Simplif ?1);Try MainSimplif) Orelse`
> `Coq` `<``((Simplif ?2);Try MainSimplif)`
> `Coq` `<``And MainSimplif:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|- ?1== ?2] -``>``Try (Simplif ?1);Try (Simplif ?2).`
> `MainSimplif is defined`
> `Simplif is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition Length trm:=`
> `Coq` `<``Match trm With`
> `Coq` `<``[?*?1] -``>`
> `Coq` `<``Let succ=(Length ?1) In`
> `Coq` `<``'(S succ)`
> `Coq` `<``|_ -``>``'(1).`
> `Length is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition Assoc:= Repeat Rewrite` `<``- Ass.`
> `Assoc is defined`
> Table 10.11: Type isomorphism tactic (1)

> 6in
> `Coq` `<``Recursive Tactic Definition DoCompare n:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|-?1==?1] -``>``Apply refl_eqT`
> `Coq` `<``|[|-(?1*?2)==(?1*?3)] -``>`
> `Coq` `<``Apply Cons;`
> `Coq` `<``Let newn=(Length ?2) In`
> `Coq` `<``(DoCompare newn)`
> `Coq` `<``|[|-(?1*?2)==?3] -``>`
> `Coq` `<``(Match Eval Compute in n With`
> `Coq` `<``[(1)] -``>``Fail`
> `Coq` `<``|_ -``>```
> `Coq` `<``Pattern 1 (?1*?2);Rewrite Com;Assoc;`
> `Coq` `<``(DoCompare '(pred n))).`
> `DoCompare is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition CompareStruct:=`
> `Coq` `<``Match Context With`
> `Coq` `<``[|-?1==?2] -``>`
> `Coq` `<``Let l1=(Length ?1)`
> `Coq` `<``And l2=(Length ?2) In`
> `Coq` `<``(Match Eval Compute in l1=l2 With`
> `Coq` `<``[?1=?1] -``>``(DoCompare ?1)).`
> `CompareStruct is defined`
> `Coq` `<```
> `Coq` `<``Tactic Definition IsoProve:=MainSimplif;CompareStruct.`
> `IsoProve is defined`
> Table 10.12: Type isomorphism tactic (2)

Table 10.13 gives examples of what can be solved by IsoProve.

> 6in
> `Coq` `<``Lemma isos_ex1:(A,B:Set)((A*unit)*B)==(B*(unit*A)).`
> `Coq` `<``Proof.`
> `Coq` `<``Intros;IsoProve.`
> `Coq` `<``Save.`
> `Coq` `<```
> `Coq` `<``Lemma isos_ex2:(A,B,C:Set)`
> `Coq` `<``((A*unit)-``>``(B*C*unit))==`
> `Coq` `<``(((A*unit)-``>``((C-``>``unit)*C))*(unit-``>``(A-``>``B))).`
> `Coq` `<``Proof.`
> `Coq` `<``Intros;IsoProve.`
> `Coq` `<``Save.`
> Table 10.13: Type equalities solved by IsoProve