packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/ple/pos/ApplicativeList.hs

{-@ LIQUID "--reflection" @-}
{-@ LIQUID "--ple"        @-}

module ListFunctors where

import Prelude hiding (fmap, id, seq, pure)

import Language.Haskell.Liquid.ProofCombinators

-- | Applicative Laws :
-- | identity      pure id <*> v = v
-- | composition   pure (.) <*> u <*> v <*> w = u <*> (v <*> w)
-- | homomorphism  pure f <*> pure x = pure (f x)
-- | interchange   u <*> pure y = pure ($ y) <*> u


{-@ reflect pure @-}
pure :: a -> L a
pure x = C x N

{-@ reflect seq @-}
seq :: L (a -> b) -> L a -> L b
seq (C f fs) xs
  = append (fmap f xs) (seq fs xs)
seq N xs
  = N

{-@ reflect append @-}
append :: L a -> L a -> L a
append N ys
  = ys
append (C x xs) ys
  = C x (append xs ys)

{-@ reflect fmap @-}
fmap f N        = N
fmap f (C x xs) = C (f x) (fmap f xs)

{-@ reflect id @-}
id :: a -> a
id x = x

{-@ reflect idollar @-}
idollar :: a -> (a -> b) -> b
idollar x f = f x

{-@ reflect compose @-}
compose :: (b -> c) -> (a -> b) -> a -> c
compose f g x = f (g x)


{-@ automatic-instances identity @-}

-- | Identity
{-@ identity :: x:L a -> { seq (pure id) x == x } @-}
identity :: L a -> Proof
identity xs
  = fmap_id xs &&& prop_append_neutral xs

-- | Composition

{-@ composition :: x:L (a -> a)
                -> y:L (a -> a)
                -> z:L a
                -> { seq (seq (seq (pure compose) x) y) z == seq x (seq y z) } @-}
composition :: L (a -> a) -> L (a -> a) -> L a -> Proof

composition N ys zs 
  =  seq_nill (pure compose)

composition (C x xs) ys zs 
  =   prop_append_neutral (fmap compose (C x xs))
  &&& prop_append_neutral (fmap compose (C x xs))
  &&& seq_append (fmap (compose x) ys) (seq (fmap compose xs) ys) zs
  &&& seq_fmap x ys zs
  &&& prop_append_neutral (fmap compose xs)
  &&& composition xs ys zs

-- | homomorphism  pure f <*> pure x = pure (f x)

{-@ homomorphism :: f:(a -> a) -> x:a
                 -> {  seq (pure f) (pure x) == pure (f x) } @-}
homomorphism :: (a -> a) -> a -> Proof
homomorphism f x
  = prop_append_neutral (C (f x) N)

-- | interchange


interchange :: L (a -> a) -> a -> Proof
{-@ interchange :: u:(L (a -> a)) -> y:a
     -> { seq u (pure y) == seq (pure (idollar y)) u }
  @-}
interchange N y
  = seq_nill (pure (idollar y))

interchange (C x xs) y
   =   prop_append_neutral (fmap (idollar y) (C x xs)) 
   &&& seq_one' (idollar y) xs 
   &&& interchange xs y
   &&& seq_prop xs y 


{-@ seq_prop :: xs:L (a -> a) -> y:a -> {seq xs (C y N) == seq xs (pure y)} @-}
seq_prop :: L (a -> a) -> a -> Proof 
seq_prop _ _ = trivial 


data L a = N | C a (L a)
{-@ data L [llen] a = N | C {x :: a, xs :: L a } @-}

{-@ measure llen @-}
llen :: L a -> Int
{-@ llen :: L a -> Nat @-}
llen N        = 0
llen (C _ xs) = 1 + llen xs


-- | TODO: Cuurently I cannot improve proofs
-- | HERE I duplicate the code...

-- TODO: remove stuff out of HERE

{-@ seq_nill :: fs:L (a -> b) -> {v:Proof | seq fs N == N } @-}
seq_nill :: L (a -> b) -> Proof
seq_nill N
  = trivial 
seq_nill (C x xs)
  = seq_nill xs

{-@ append_fmap :: f:(a -> b) -> xs:L a -> ys: L a
      -> {append (fmap f xs) (fmap f ys) == fmap f (append xs ys) } @-}
append_fmap :: (a -> b) -> L a -> L a -> Proof
append_fmap _ N _         = trivial 
append_fmap f (C _ xs) ys = append_fmap f xs ys  

seq_fmap :: (a -> a) -> L (a -> a) -> L a -> Proof
{-@ seq_fmap :: f: (a -> a) -> fs:L (a -> a) -> xs:L a
         -> { seq (fmap (compose f) fs) xs == fmap f (seq fs xs) }
  @-}
seq_fmap _ N _         = trivial
seq_fmap f (C g gs) xs
  =   seq_fmap f gs xs 
  &&& append_fmap f (fmap g xs) (seq gs xs) 
  &&& map_fusion0 f g xs

{-@ append_distr :: xs:L a -> ys:L a -> zs:L a
      -> {v:Proof | append xs (append ys zs) == append (append xs ys) zs } @-}
append_distr :: L a -> L a -> L a -> Proof
append_distr N _ _ = trivial
append_distr (C _ xs) ys zs = append_distr xs ys zs 


{-@ seq_one' :: f:((a -> b) -> b) -> xs:L (a -> b) -> {fmap f xs == seq (pure f) xs} @-}
seq_one' :: ((a -> b) -> b) -> L (a -> b) -> Proof
seq_one' _ N = trivial
seq_one' f (C _ xs) = seq_one' f xs 

{-@ seq_one :: xs:L (a -> b) -> {v:Proof | fmap compose xs == seq (pure compose) xs} @-}
seq_one :: L (a -> b) -> Proof
seq_one N = trivial
seq_one (C _ xs) = seq_one xs 

{-@ seq_append :: fs1:L (a -> b) -> fs2: L (a -> b) -> xs: L a
      -> { seq (append fs1 fs2) xs == append (seq fs1 xs) (seq fs2 xs) } @-}
seq_append :: L (a -> b) -> L (a -> b) -> L a -> Proof
seq_append N _ _ = trivial 
seq_append (C f1 fs1) fs2 xs 
  =   append_distr (fmap f1 xs) (seq fs1 xs) (seq fs2 xs) 
  &&& seq_append fs1 fs2 xs 

{-@ map_fusion0 :: f:(a -> a) -> g:(a -> a) -> xs:L a
      -> {v:Proof | fmap (compose f g) xs == fmap f (fmap g xs) } @-}
map_fusion0 :: (a -> a) -> (a -> a) -> L a -> Proof
map_fusion0 _ _ N = trivial
map_fusion0 f g (C _ xs) = map_fusion0 f g xs


-- | FunctorList
{-@ fmap_id :: xs:L a -> {v:Proof | fmap id xs == id xs } @-}
fmap_id :: L a -> Proof
fmap_id N
  = trivial
fmap_id (C x xs)
  = fmap_id xs

-- imported from Append
prop_append_neutral :: L a -> Proof
{-@ prop_append_neutral :: xs:L a -> {v:Proof | append xs N == xs }  @-}
prop_append_neutral N
  = trivial 
prop_append_neutral (C x xs)
  = prop_append_neutral xs