packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/nople/pos/ApplicativeReader.hs

{-@ LIQUID "--higherorder"     @-}
{-@ LIQUID "--exact-data-cons" @-}
{-@ LIQUID "--alphaequivalence" @-}
{-@ LIQUID "--betaequivalence" @-}

{-# LANGUAGE IncoherentInstances   #-}
{-# LANGUAGE FlexibleContexts #-}
module ApplicativeReader where

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

import Proves
import Helper (lambda_expand)

-- | 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

{-@ data Reader r a = Reader { runIdentity :: r -> a } @-}
data Reader r a     = Reader { runIdentity :: r -> a }

{-@ measure fromReader @-}
fromReader :: Reader r a -> (r -> a)
fromReader (Reader f) = f 


{-@ axiomatize pure @-}
pure :: a -> Reader r a
pure x = Reader (\r -> x)

{-@ axiomatize seq @-}
seq :: Reader r (a -> b) -> Reader r a -> Reader r b
seq (Reader f) (Reader x) = Reader (\r -> (f r) (x r))

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

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

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

-- | Identity

{-@ identity :: x:Reader r a 
  -> { seq (pure id) x == x } @-}
identity :: Arg r => Reader r a -> Proof
identity (Reader r)
  =   seq (pure id) (Reader r)
  ==. seq (Reader (\w -> id)) (Reader r)
  ==. Reader (\q -> ((\w -> id) (q)) (r q))   
  ==. Reader (\q -> (id) (r q))            ? id_helper1 r
  ==. Reader (\q -> r q)                   ? id_helper2 r 
  ==. Reader r                             ? lambda_expand r 
  *** QED 


-- NV: The following are the required helper functions as 
-- we have no other way to prove equalities burried in lambdas. 
-- This should be simplified

 

id_helper2 :: Arg r => (r -> a) -> Proof 
{-@ id_helper2 :: r:(r -> a) 
  -> { (\q:r -> r q) == (\q:r -> (id) (r q)) } @-}
id_helper2 r 
  = ((\q -> r q) =*=: (\q -> (id) (r q))) (id_helper2_body r)
  *** QED 


id_helper2_body :: Arg r => (r -> a) -> r ->  Proof 
{-@ id_helper2_body :: r:(r -> a) -> q:r
  -> { (r q == (id) (r q)) 
    && (( (\q:r -> r q) (q)) == r q)
    && (((\q:r -> (id) (r q)) (q)) == id (r q))
     } @-}
id_helper2_body r q
  = r q ==. id (r q) *** QED 


id_helper1 :: Arg r => (r -> a) -> Proof 
{-@ id_helper1 :: r:(r -> a) 
  -> { (\q:r -> (((\w:r -> id) (q)) (r q))) == (\q:r -> (id) (r q)) } @-}
id_helper1 r 
  = ((\q -> (((\w -> id) q) (r q))) =*=: (\q -> id (r q))) (id_helper1_body r)
  *** QED 
{-@ id_helper1_body :: r:(r -> a) -> q:r
  -> {(((\w:r -> id) (q)) (r q)) == (id) (r q) } @-}
id_helper1_body :: Arg r => (r -> a) -> r -> Proof 
id_helper1_body r q 
  =   ((\w -> id) q) (r q)
  ==. id (r q)
  *** QED   



-- | Composition

{-@ composition :: x:Reader r (a -> a)
                -> y:Reader r (a -> a)
                -> z:Reader r a
                -> { seq (seq (seq (pure compose) x) y) z == seq x (seq y z) } @-}
composition :: Arg r => Reader r (a -> a) -> Reader r (a -> a) -> Reader r a -> Proof
composition (Reader x) (Reader y) (Reader z)
  =   seq (seq (seq (pure compose)            (Reader x))     (Reader y)) (Reader z) 
  ==. seq (seq (seq (Reader (\r1 -> compose)) (Reader x))     (Reader y)) (Reader z)
  ==. seq (seq (Reader (\r2 -> ((\r1 -> compose) r2) (x r2))) (Reader y)) (Reader z)
  ==. seq (seq (Reader (\r2 -> compose (x r2)))               (Reader y)) (Reader z)
  ==. seq (Reader (\r3 -> ((\r2 -> compose (x r2)) (r3)) (y r3)))         (Reader z) 
  ==. seq (Reader (\r3 -> (compose (x r3))               (y r3)))         (Reader z)
  ==. Reader (\r4 -> ((\r3 -> (compose (x r3)) (y r3)) r4) (z r4)) 
  ==. Reader (\r4 -> (compose (x r4) (y r4)) (z r4)) 
      ? composition_helper1 x y z 
  ==. Reader (\r4 -> (x r4) ((y r4) (z r4)))
  ==. Reader (\r4 -> (x r4) ((\r5 -> (y r5) (z r5)) (r4)))
  ==. seq (Reader x) (Reader (\r5 -> (y r5) (z r5)))
  ==. seq (Reader x) (seq (Reader y) (Reader z))
  *** QED 

composition_helper1 :: Arg r => (r -> (a -> a)) -> (r -> (a -> a)) -> (r -> a) -> Proof 
{-@ composition_helper1 
    :: x:(r -> (a -> a)) -> y:(r -> (a -> a)) -> z:(r -> a) 
    -> {(\r4:r -> (compose (x r4) (y r4)) (z r4))  == (\r4:r -> (x r4) ((y r4) (z r4))) }
  @-}
composition_helper1 x y z = undefined  

-- | 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
  =   seq (pure f) (pure x)
  ==. seq (Reader (\r2 -> f)) (Reader (\r2 -> x))
  ==. Reader (\r -> ((\r2 -> f) r ) ((\r2 -> x) r))
  ==. Reader (\r -> f x)
  ==. pure (f x)
  *** QED 

-- | interchange

interchange :: Arg r => Reader r (a -> a) -> a -> Proof
{-@ interchange :: u:(Reader r (a -> a)) -> y:a
     -> { seq u (pure y) == seq (pure (idollar y)) u }
  @-}
interchange (Reader f) x
  =   seq (Reader f) (pure x)
  ==. seq (Reader f) (Reader (\r -> x))
  ==. Reader (\r' -> (f r') ((\r -> x) r'))
  ==. Reader (\r' -> (f r') x)                           ? interchange_helper_0 f x -- this is not required
  ==. Reader (\r' -> (idollar x) (f r'))                 ? interchange_helper_1 f x 
  ==. Reader (\r' -> ((\r'' -> (idollar x)) r') (f r'))  ? interchange_helper_2 f x 
  ==. seq (Reader (\r'' ->  (idollar x))) (Reader f)
  ==. seq (pure (idollar x)) (Reader f)
  *** QED 


{-@ interchange_helper_0
  :: f:(r -> (a -> a)) -> x:a 
  -> {(\r':r -> (f r') (x)) == (\r':r -> (f r') ((\r:r -> x) (r')) )}
  @-} 
interchange_helper_0 :: Arg r => (r -> (a -> a)) -> a -> Proof 
interchange_helper_0 f x
  = (((\r -> (f r) x) =*=: (\r -> (f r) ((\r' -> x) r))) 
    (\_ -> simpleProof)) *** QED  


{-@ interchange_helper_1 
  :: f:(r -> (a -> a)) -> x:a 
  -> {(\r':r -> (f r') (x)) == (\r':r -> (idollar x) (f r'))}
  @-} 
interchange_helper_1 :: Arg r => (r -> (a -> a)) -> a -> Proof 
interchange_helper_1 f x 
  =  (((\r -> (f r) x) =*=: (\r -> (idollar x) (f r))) (interchange_helper_1_body f x)) *** QED 

{-@ interchange_helper_1_body 
  :: f:(r -> (a -> a)) -> x:a -> r':r
  -> {((f r') (x) == (idollar x) (f r'))
     && ((\r':r -> (f r') (x)) (r')  ==  (f r') (x))
     && ((\r':r -> (idollar x) (f r')) (r') == (idollar x) (f r'))
     }
  @-} 
interchange_helper_1_body :: Arg r => (r -> (a -> a)) -> a -> r -> Proof 
interchange_helper_1_body f x r 
  = f r x ==. (idollar x) (f r) *** QED 


{-@ interchange_helper_2 
  :: f:(r -> (a -> a)) -> x:a 
  -> {(\r':r -> ((\r'':r -> (idollar x)) (r')) (f r')) == (\r':r -> (idollar x) (f r'))}
  @-} 
interchange_helper_2 :: Arg r => (r -> (a -> a)) -> a -> Proof 
interchange_helper_2 f x 
  =    (((\r' -> ((\r'' -> (idollar x)) (r')) (f r')) ) 
  =*=: (\r' -> (idollar x) (f r'))
       ) (interchange_helper_2_body f x) *** QED 

{-@ interchange_helper_2_body 
  :: f:(r -> (a -> a)) -> x:a -> r':r
  -> {(\r':r -> ((\r'':r -> (idollar x)) (r')) (f r')) == (\r':r -> (idollar x) (f r'))}
  @-} 
interchange_helper_2_body :: Arg r => (r -> (a -> a)) -> a -> r -> Proof 
interchange_helper_2_body f x r'
  =    ((\r'' -> (idollar x)) (r')) (f r')
  ==.  (idollar x) (f r')
  *** QED 





{-@ qual :: f:(r -> a) -> {v:Reader r a | v == Reader f} @-}
qual :: (r -> a) -> Reader r a 
qual = Reader