diff --git a/content/blog/coq_palindrome.md b/content/blog/coq_palindrome.md index d46d72e..6ce1105 100644 --- a/content/blog/coq_palindrome.md +++ b/content/blog/coq_palindrome.md @@ -14,7 +14,7 @@ Of course, my definition led to only having palindromes of even length. In order * A list with a single value is a palindrome. This translates readily into Coq: -``` +```Coq Inductive palindrome { X : Type } : list X -> Prop := | palindrome_nil : palindrome [] | palindrome_x : forall (x : X), palindrome [x] @@ -24,7 +24,7 @@ Inductive palindrome { X : Type } : list X -> Prop := ### The first direction It’s nearly trivial to show that a palindrome is its own inverse: -``` +```Coq Theorem pal_rev { X : Type } : forall (l : list X), palindrome l -> l = rev l. Proof. intros l H. @@ -49,7 +49,7 @@ Then, the proposition holds for all values of that type. This can be easily seen As I was working with my definition of a palindrome, it dawned on me that generalizing a single variable in that definition would create another inductive definition of a list. If we change the inductive rule in the palindrome definition from saying “surrounding another palindrome with x on both sides” to “surrounding another list with some x on one side and some y on the other”, we can effectively construct any list. We can then state a different structural induction principle: -``` +```Coq Theorem alt_induction { X : Type } : forall (P : list X -> Prop), P [] -> (forall (x : X), P [x]) -> @@ -61,7 +61,7 @@ But how would we go about proving this? If we try to just use induction on `ln`, #### Proving Equivalence What’s missing is that there’s nothing as yet stating that appending values to the back and the front of another list is an equivalent way to appending a value only to the front of a list. We need to state this explicitly; but how? I decided that the easiest way would be by defining a new inductive property, `list_alt` which holds for all lists that can be constructed by adding things to the back and the front. Then, we can show that it holds for all lists, and, therefore, that any list can be constructed this way. I defined the property as such: -``` +```Coq Inductive list_alt { X : Type } : list X -> Prop := | list_alt_base : list_alt [] | list_alt_x : forall (x : X), list_alt [x] @@ -70,7 +70,7 @@ Inductive list_alt { X : Type } : list X -> Prop := Then, to prove it true for all lists, I first showed what is effectively the inductive hypothesis of a proof by induction on the structure of a list: -``` +```Coq Theorem list_alt_cons { X : Type } : forall (x : X) (l : list X), list_alt l -> list_alt (x::l). Proof. @@ -91,7 +91,7 @@ Qed. ``` Next, the actual proof of equivalence simply used the previous theorem: -``` +```Coq Theorem list_alt_correct { X : Type } : forall (l : list X), list_alt l. Proof. induction l. @@ -102,7 +102,7 @@ Qed. Finally, we can prove our custom principle of induction (by induction (!) on the property list_alt, which we now know holds for all lists): -``` +```Coq Theorem alt_induction { X : Type } : forall (P : list X -> Prop), P [] -> (forall (x : X), P [x]) -> @@ -118,7 +118,7 @@ Proof. Finally, the palindrome proof can simply use this principle. Coq turns out to have a mechanism to use a custom induction principle via `induction … using …`: -``` +```Coq Theorem rev_pal' { X : Type } : forall (l : list X), l = rev l -> palindrome l. Proof. intros l H. induction l using alt_induction.