liquidhaskell-0.8.2.0: tests/equationalproofs/pos/AppendVerbose.hs
-- | A first example in equalional reasoning.
-- | From the definition of append we should be able to
-- | semi-automatically prove the two axioms.
-- | Note for soundness we need
-- | totallity: all the cases should be covered
-- | termination: we cannot have diverging things into proofs
{-@ LIQUID "--totality" @-}
module Append where
import Language.Haskell.Liquid.Prelude
data L a = N | C a (L a) deriving (Eq)
{-@ N :: {v:L a | llen v == 0 && v == N } @-}
{-@ C :: x:a -> xs:L a -> {v:L a | llen v == llen xs + 1 && v == C x xs } @-}
{-@ data L [llen] @-}
{-@ invariant {v: L a | llen v >= 0} @-}
{-@ measure llen :: L a -> Int @-}
llen :: L a -> Int
llen N = 0
llen (C x xs) = 1 + llen xs
append :: L a -> L a -> L a
append N xs = xs
append (C y ys) xs = C y (append ys xs)
-- | All the followin will be autocatically generated by the definition of append
-- | and a liquid annotation
-- |
-- | axiomatize append
-- |
{-@ measure append :: L a -> L a -> L a @-}
{-@ assume append :: xs:L a -> ys:L a -> {v:L a | v == append xs ys } @-}
{-@ assume axiom_append_nil :: xs:L a -> {v:Proof | append N xs == xs} @-}
axiom_append_nil :: L a -> Proof
axiom_append_nil xs = Proof
{-@ assume axiom_append_cons :: x:a -> xs: L a -> ys: L a
-> {v:Proof | append (C x xs) ys == C x (append xs ys) } @-}
axiom_append_cons :: a -> L a -> L a -> Proof
axiom_append_cons x xs ys = Proof
-- | Proof library:
data Proof = Proof
{-@ toProof :: l:a -> r:{a|l = r} -> {v:Proof | l = r } @-}
toProof :: a -> a -> Proof
toProof x y = Proof
{-@ (===) :: l:a -> r:a -> {v:Proof | l = r} -> {v:a | v = l } @-}
(===) :: a -> a -> Proof -> a
(===) x y _ = y
-- | Proof 1: N is neutral element
{-@ prop_nil :: xs:L a -> {v:Proof | (append xs N == xs) } @-}
prop_nil :: Eq a => L a -> Proof
prop_nil N = axiom_append_nil N
prop_nil (C x xs) = toProof e1 $ ((
e1 === e2) pr1
=== e3) pr2
where
e1 = append (C x xs) N
pr1 = axiom_append_cons x xs N
e2 = C x (append xs N)
pr2 = prop_nil xs
e3 = C x xs
-- | Proof 2: append is associative
{-@ prop_assoc :: xs:L a -> ys:L a -> zs:L a
-> {v:Proof | (append (append xs ys) zs == append xs (append ys zs))} @-}
prop_assoc :: Eq a => L a -> L a -> L a -> Proof
prop_assoc N ys zs =
toProof (append (append N ys) zs) $ ((
append (append N ys) zs === append ys zs) (axiom_append_nil ys)
=== append N (append ys zs)) (axiom_append_nil (append ys zs))
prop_assoc (C x xs) ys zs =
toProof e1 $ ((((
e1 === e2) pr1
=== e3) pr2
=== e4) pr3
=== e5) pr4
where
e1 = append (append (C x xs) ys) zs
pr1 = axiom_append_cons x xs ys
e2 = append (C x (append xs ys)) zs
pr2 = axiom_append_cons x (append xs ys) zs
e3 = C x (append (append xs ys) zs)
pr3 = prop_assoc xs ys zs
e4 = C x (append xs (append ys zs))
pr4 = axiom_append_cons x xs (append ys zs)
e5 = append (C x xs) (append ys zs)