sum
and psum
mRTheorem
mRTheorem
on plusWe already saw how to prove properties on integers using induction on natural numbers. Next, we will see how to prove properties on algebraic data types using structural induction.
As expected, we will prove properties of functions that manipulate the most common algebraic data type, lists.
Next, we define and reflect two functions, map
and id
, that we will use to illustrate structural induction on lists.
The first property we will prove is that mapping the identity function over a list is the same as the identity over the list.
This property can be used as an optimization pass, in the right hand side, the list is not traversed by map!
The proof goes by structural induction on the list the list xs
.
xs
is []
, which goes by rewriting.xs
is x:xs
, which goes by rewriting and the induction hypothesis.Note that Liquid Haskell checks both that both cases are defined (by totality) and that the inductive call is well-founded (by termination).
As before, ple
can be used to automate the proof. We essentially need to keep the case splitting and the induction hypothesis.
Next, we will prove that mapping two functions over a list is the same as mapping the composition of the functions over the list.
For this we define the composition of two functions.
Question: Let’s prove map fusion.
Lists form a monoid structure, in that they have an associative binary operation (list append) and a neutral element (empty list):
Monoid structures have three laws: associativity, left identity and right identity. So, let’s prove these laws for lists.
empty
is the left identity for append
.empty
is the right identity for append
.append
is associative.As a final example, let’s define list reversing and prove that reverse distributes over append.
Question: Let’s prove distributivity. Hint, you can use the proved lemmas emptyRightIdentity
and appendAssoc
.
Liquid Haskell has a (beta) tactic that allows the proof to get automated using existing equations proved in lemmas. Thus the proof can be automated as follows:
{-@ rewriteWith distributivity [appendAssoc, emptyRightIdentity] @-}
We saw how to use Liquid Haskell to encode proofs of structural induction on lists. We proved the functor and monoid laws for lists and distributivity of reverse over append, using the two Liquid Haskell tactics of ple
and rewriteWith
.