Idris2/libs/contrib/Data/List/Palindrome.idr

61 lines
2.1 KiB
Idris

module Data.List.Palindrome
import Data.List
import Data.List.Views
import Data.List.Views.Extra
import Data.List.Reverse
import Data.List.Equalities
%hide Prelude.reverse
%default total
||| Do geese see God?
public export
data Palindrome : (xs : List a) -> Type where
Empty : Palindrome []
Single : Palindrome [_]
Multi : Palindrome xs -> Palindrome (x :: (xs `snoc` x))
||| A Palindrome reversed is itself.
export
palindromeReverse : (xs : List a) -> Palindrome xs -> reverse xs = xs
palindromeReverse [] Empty = Refl
palindromeReverse [_] Single = Refl
palindromeReverse ([x] ++ ys ++ [x]) (Multi pf) =
rewrite sym $ revAppend ([x] ++ ys) [x] in
rewrite sym $ revAppend [x] ys in
rewrite palindromeReverse ys pf in
Refl
private
reversePalindromeEqualsLemma
: (x, x' : a)
-> (xs : List a)
-> reverse (x :: (xs ++ [x'])) = (x :: (xs ++ [x']))
-> (reverse xs = xs, x = x')
reversePalindromeEqualsLemma x x' xs prf = equateInnerAndOuter flipHeadX
where
flipHeadX : reverse (xs ++ [x']) ++ [x] = x :: (xs ++ [x'])
flipHeadX = rewrite (sym (reverseCons x (xs ++ [x']))) in prf
flipLastX' : reverse (xs ++ [x']) = x :: xs -> (x' :: reverse xs) = (x :: xs)
flipLastX' prf = rewrite (revAppend xs [x']) in prf
cancelOuter : (reverse (xs ++ [x'])) = x :: xs -> reverse xs = xs
cancelOuter prf = snd (consInjective (flipLastX' prf))
equateInnerAndOuter
: reverse (xs ++ [x']) ++ [x] = (x :: xs) ++ [x']
-> (reverse xs = xs, x = x')
equateInnerAndOuter prf =
let (prf', xEqualsX') = snocInjective prf
in (cancelOuter prf', xEqualsX')
||| Only Palindromes are equal to their own reverse.
export
reversePalindrome : (xs : List a) -> reverse xs = xs -> Palindrome xs
reversePalindrome input prf with (vList input)
reversePalindrome [] _ | VNil = Empty
reversePalindrome [x] _ | VOne = Single
reversePalindrome (x :: (inner `snoc` y)) prf | VCons rec with (reversePalindromeEqualsLemma x y inner prf)
reversePalindrome (x :: (inner `snoc` y)) prf | VCons rec | (revInnerIsIdentical, xIsY) =
rewrite xIsY in
Multi $ reversePalindrome inner revInnerIsIdentical | Force rec