Palindromes are lists that read the same from left to right and from right to left.
For example, [a, b, b, a] and [a, h, a] are palindromes.
We use an inductive predicate to specify whether a list is a palindrome or not.
Recall that inductive predicates, or inductively defined propositions, are a convenient
way to specify functions of type ... → Prop.
This example is a based on an example from the book "The Hitchhiker's Guide to Logical Verification".
The definition distinguishes three cases: (1) [] is a palindrome; (2) for any element
a, the singleton list [a] is a palindrome; (3) for any element a and any palindrome
[b₁, . . ., bₙ], the list [a, b₁, . . ., bₙ, a] is a palindrome.
We now prove that the reverse of a palindrome is a palindrome using induction on the inductive predicate h : Palindrome as.
Given a nonempty list, the function List.last returns its element.
Note that we use (by simp) to prove that a₂ :: as ≠ [] in the recursive application.
We use the function List.last to prove the following theorem that says that if a list as is not empty,
then removing the last element from as and appending it back is equal to as.
We use the attribute @[simp] to instruct the simp tactic to use this theorem as a simplification rule.
We now define the following auxiliary induction principle for lists using well-founded recursion on as.length.
We can read it as follows, to prove motive as, it suffices to show that: (1) motive []; (2) motive [a] for any a;
(3) if motive as holds, then motive ([a] ++ as ++ [b]) also holds for any a, b, and as.
Note that the structure of this induction principle is very similar to the Palindrome inductive predicate.
We use our new induction principle to prove that if as.reverse = as, then Palindrome as holds.
Note that we use the using modifier to instruct the induction tactic to use this induction principle
instead of the default one for lists.
We now define a function that returns true iff as is a palindrome.
The function assumes that the type α has decidable equality. We need this assumption
because we need to compare the list elements.