packages feed

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)