packages feed

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

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

-- NOPROP probably breaks some fixpoint flag 

{-@ LIQUID "--alphaequivalence"  @-}
{-@ LIQUID "--betaequivalence"   @-}
{-@ LIQUID "--normalform"        @-} 

{-# LANGUAGE IncoherentInstances #-}
{-# LANGUAGE FlexibleContexts    #-}

module MonadReader where

import Prelude hiding (return, Maybe(..), (>>=))

import Proves
import Helper 

-- | Monad Laws :
-- | Left identity:	  return a >>= f  ≡ f a
-- | Right identity:	m >>= return    ≡ m
-- | Associativity:	  (m >>= f) >>= g ≡	m >>= (\x -> f x >>= g)

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

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

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

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

-- NV TODO the following is needed because Reader is not interpreted by
-- Contraints.Generate.lamExpr

{-@ axiomatize reader @-}
reader x = Reader x 

 
{-@ readerId :: f:(Reader r a) -> {f == Reader (fromReader f)} @-} 
readerId :: (Reader r a) -> Proof 
readerId (Reader f)  
  =   Reader (fromReader (Reader f))
  ==. Reader f 
  *** QED 


-- | Left Identity
{-@ left_identity :: x:a -> f:(a -> Reader r b) -> { bind (return x) f == f x } @-}
left_identity :: Arg r => a -> (a -> Reader r b) -> Proof
left_identity x f
  =   bind (return x) f 
  ==. bind (Reader (\r -> x)) f
  ==. Reader (\r' -> fromReader (f ((\r -> x) r')) r')
  ==. Reader (\r' -> fromReader (f x) r') ? left_identity_helper x f 
  ==. Reader (fromReader (f x)) ? lambda_expand (fromReader (f x))
  ==. f x                       ? readerId (f x)
  *** QED 


{-@ left_identity_helper :: x:a -> f:(a -> Reader r b) 
  -> {  (\r':r -> (fromReader (f ((\r:r -> x) (r')) ) (r'))) ==  (\r':r -> (fromReader (f x) (r')))  } @-}
left_identity_helper :: Arg r => a -> (a -> Reader r b) -> Proof
left_identity_helper x f
  =   simpleProof

-- | Right Identity


{-@ right_identity :: x:Reader r a -> { bind x return == x }
 @-}
right_identity :: Arg r => Reader r a -> Proof
right_identity (Reader x)
  =   bind (Reader x) return
  ==. Reader (\r -> fromReader (return (x r)) r)
  ==. Reader (\r -> fromReader (reader (\r' ->  (x r))) (r))
       ? right_identity_helper x 
  ==. Reader (\r -> (\r' ->  (x r)) (r)) 
       ? right_identity_helper1 x 
  ==. Reader (\r -> x r)           
       -- ? right_identity_helper2 x       
  ==. Reader x                           
       ? lambda_expand x 
  *** QED 


right_identity_helper1 :: Arg r => (r -> a) -> Proof 
{-@ right_identity_helper1 :: Arg r => x:(r -> a) 
  -> {(\r:r -> fromReader (reader (\r':r ->  (x r))) (r)) == (\r:r -> (\r':r ->  (x r)) (r))} @-}
right_identity_helper1 x =
  ((\r -> (\r' ->  (x r)) (r)) =*=: (\r -> fromReader (reader (\r' ->  (x r))) (r)))
    (right_identity_helper1_body x) *** QED 


right_identity_helper1_body :: Arg r => (r -> a) -> r -> Proof 
{-@ right_identity_helper1_body :: Arg r => x:(r -> a) -> r:r 
  -> {(fromReader (reader (\r':r ->  (x r))) (r) == (\r':r ->  (x r)) (r))
    && ((\r:r -> fromReader (reader (\r':r ->  (x r))) (r)) (r) == (fromReader (reader (\r':r ->  (x r))) (r))) 
    && ((\r:r -> (\r':r ->  (x r)) (r)) (r) == ((\r':r ->  (x r)) (r)))
    } @-}
right_identity_helper1_body x r
  =  fromReader (reader (\r' -> (x r))) r 
  ==. (\r' -> x r) r 
  *** QED 


right_identity_helper2 :: Arg r => (r -> a) -> Proof 
{-@ right_identity_helper2 :: Arg r => x:(r -> a) 
  -> { (\r:r -> (\r':r ->  (x r)) (r)) ==  (\r:r -> x r) } @-}
right_identity_helper2 _ = simpleProof


right_identity_helper :: Arg r => (r -> a) -> Proof 
{-@ right_identity_helper :: Arg r => x:(r -> a) 
  -> {(\r:r -> fromReader (return (x r)) r) == (\r:r -> fromReader (reader (\r':r ->  (x r))) (r))} @-}
right_identity_helper x
  =  (
     (\r -> fromReader (return (x r)) r)
     =*=: 
     (\r -> fromReader (reader (\r' ->  (x r))) (r))
     )  (right_identity_helper_body x) *** QED 

right_identity_helper_body :: Arg r => (r -> a) -> r -> Proof 
{-@ right_identity_helper_body :: Arg r => x:(r -> a) -> r:r
  -> { (fromReader (return (x r)) r == fromReader (reader (\r':r ->  (x r))) (r))
       && (((\r:r -> fromReader (return (x r)) r)) (r) == (fromReader (return (x r)) r))
       && ((\r:r -> fromReader (reader (\r':r ->  (x r))) (r))(r) == (fromReader (reader (\r':r ->  (x r))) (r)))
      } @-}
right_identity_helper_body x r 
  =   fromReader (return (x r)) r
  ==. fromReader (reader (\r' ->  (x r))) r
  *** QED 

-- | Associativity:	  (m >>= f) >>= g ≡	m >>= (\x -> f x >>= g)
{-@ associativity :: x:Reader r a -> f: (a -> Reader r a) -> g:(a -> Reader r a) 
  -> {bind (bind x f) g      ==  bind x (\r4:a ->(bind (f r4) g)) } @-}
associativity :: (Arg r, Arg a) =>  Reader r a -> (a -> Reader r a) -> (a -> Reader r a) -> Proof
associativity (Reader x) f g
  =   bind (bind (Reader x) f) g
  -- unfold inner bind 
  ==. bind (Reader (\r1 -> fromReader (f (x r1)) r1)) g 
  -- unfold outer bind 
  ==. Reader (\r2 -> fromReader (g ((\r1 -> fromReader (f (x r1)) r1) (r2))) (r2))
  -- apply    r1 := r2
  ==. Reader (\r2 -> fromReader (g (fromReader (f (x r2)) r2) )  r2)
  -- abstract r3 := r2 
  ==. Reader (\r2 -> 
          (\r3 -> fromReader (g ((fromReader (f (x r2))) r3) ) r3)
         r2)
  -- apply measure fromReader (Reader f) == f 
  ==. Reader (\r2 -> fromReader (
          (reader (\r3 -> fromReader (g ((fromReader (f (x r2))) r3) ) r3))
        ) r2)
        ? associativity_helper0 x f g 
  -- abstract r4 := x r2 
  ==. Reader (\r2 -> fromReader ((\r4 -> 
          (reader (\r3 -> fromReader (g ((fromReader (f r4)) r3) ) r3))
        ) (x r2)) r2) 
      ? associativity_helper2 x f g 
  -- fold (bind (f r4) g)
  ==. Reader (\r2 -> fromReader ((\r4 -> 
           (bind (f r4) g)
        ) (x r2)) r2)  
     ? associativity_helper1 x f g 
  -- fold bind 
  ==. bind (Reader x) (\r4 ->(bind (f r4) g))
  *** QED  

{-@ associativity_helper0 :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) 
  -> {  (\r2:r -> (\r3:r -> fromReader (g (fromReader (f ( x r2)) r3)) (r3)) (r2)) 
      ==   (\r2:r -> (fromReader (reader (\r3:r -> fromReader (g (fromReader (f (x r2)) r3)) (r3)))) (r2)) 
          } @-}
associativity_helper0 :: Arg r => (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> Proof
associativity_helper0 x f g
  =    ((\r2 -> (\r3 -> fromReader (g (fromReader (f ( x r2)) r3)) (r3)) (r2)) 
  =*=:  (\r2 -> fromReader (reader (\r3 -> fromReader (g (fromReader (f (x r2)) r3)) (r3))) (r2)))
         (associativity_helper0_body x f g) *** QED 
          
associativity_helper0_body :: (r -> a) -> (a -> Reader r b) -> (b -> Reader r c)-> r  -> Proof
{-@ associativity_helper0_body :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) -> r2:r
  -> {    (\r3:r -> fromReader (g (fromReader (f ( x r2)) r3)) (r3)) (r2)
      ==  (fromReader (reader (\r3:r -> fromReader (g (fromReader (f (x r2)) r3)) (r3)))) (r2)
       && 
           ((\r2:r -> (\r3:r -> fromReader (g (fromReader (f ( x r2)) r3)) (r3)) (r2))) (r2) == (\r3:r -> fromReader (g (fromReader (f ( x r2)) r3)) (r3)) (r2)
       && 
           (\r2:r -> (fromReader (reader (\r3:r -> fromReader (g (fromReader (f (x r2)) r3)) (r3)))) (r2)) (r2) == (fromReader (reader (\r3:r -> fromReader (g (fromReader (f (x r2)) r3)) (r3)))) (r2)
          } @-}
associativity_helper0_body x f g r2
  = readerId' (\r3 -> fromReader (g (fromReader (f ( x r2)) r3)) (r3))

{-@ readerId' :: x:(r -> a) -> {x == fromReader (reader x)} @-} 
readerId' :: (r -> a) -> Proof 
readerId' x  
  =   fromReader (reader x)
  ==. fromReader (Reader x)
  ==. x 
  *** QED 


{-@ associativity_helper2 :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) 
  -> {  (\r2:r -> fromReader (reader (\r3:r -> fromReader (g (fromReader (f (x r2)) r3)) (r3))) (r2))  
      ==   (\r2:r -> fromReader ( (\r4:a -> ( reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2))  
         } @-}
associativity_helper2 :: (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> Proof
associativity_helper2 x f g = simpleProof

{-@ associativity_helper1 :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) 
  -> {   (\r2:r -> fromReader ( (\r4:a -> ( reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2))  
      ==    (\r2:r -> fromReader ( (\r4:a -> ( bind (f r4) g))  (x r2)) (r2))  
    } @-}
associativity_helper1 :: (Arg r, Arg a) => (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> Proof
associativity_helper1 x f g
  = ((\r2 -> fromReader ( (\r4 -> ( reader (\r3 -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2))  
      =*=:    (\r2 -> fromReader ( (\r4 -> ( bind (f r4) g))  (x r2)) (r2))  
    ) (associativity_helper1_body x f g)  *** QED 

{-@ associativity_helper1_body :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) -> r2:r
  -> {  fromReader ( (\r4:a -> ( reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2)  
      ==   fromReader ( (\r4:a -> ( bind (f r4) g))  (x r2)) (r2)
      && 
        ((\r2:r -> fromReader ( (\r4:a -> ( reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2))) (r2)
        == fromReader ( (\r4:a -> ( reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2)
      && 
        (\r2:r -> fromReader ( (\r4:a -> ( bind (f r4) g))  (x r2)) (r2)) (r2)
        == fromReader ( (\r4:a -> ( bind (f r4) g))  (x r2)) (r2)
    } @-}
associativity_helper1_body :: (Arg r, Arg a ) => (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> r -> Proof
associativity_helper1_body x f g r2 
  =   fromReader ( (\r4 -> ( reader (\r3 -> fromReader (g (fromReader (f r4 ) r3)) (r3))))  (x r2)) (r2)
  ==. fromReader ( (\r4 -> ( bind (f r4) g))  (x r2)) (r2)
      ? helper_of_helper x f g r2
  *** QED 


{-@ helper_of_helper :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) -> r2:r
  -> {   \r4:a -> (reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3)))
      == \r4:a -> (bind (f r4) g)
    } @-}
helper_of_helper :: (Arg r, Arg a) => (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> r -> Proof
helper_of_helper x f g r2 
  =  ( (\r4 -> (reader (\r3 -> fromReader (g (fromReader (f r4 ) r3)) (r3))))
      =*=: (\r4 -> (bind (f r4) g))) (helper_of_helper_body x f g r2) *** QED 

{-@ helper_of_helper_body :: x:(r -> a) -> f:(a -> Reader r b) -> g:(b -> Reader r c) -> r2:r -> r4:a
  -> {   (reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3)))
      == (bind (f r4) g)
      && 
         (\r4:a -> (reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3)))) (r4)
      ==  (reader (\r3:r -> fromReader (g (fromReader (f r4 ) r3)) (r3)))
      && 
         (\r4:a -> (bind (f r4) g)) (r4) == (bind (f r4) g)

    } @-}
helper_of_helper_body :: Arg r => (r -> a) -> (a -> Reader r b) -> (b -> Reader r c) -> r -> a -> Proof
helper_of_helper_body x f g r2 r4 
  = case f r4 of 
      Reader _ -> reader (\r3 -> fromReader (g (fromReader (f r4 ) r3)) (r3)) 
                  ==. bind (f r4) g 
                   *** QED 



{-@ helper_of_helper_body' :: x:(r -> a) -> y:(Reader r b) -> g:(b -> Reader r c) -> r2:r -> r4:a
  -> {   (Reader (\r3:r -> fromReader (g ( (fromReader y) (r3))) (r3)))
      == (bind y g)
    } @-}
helper_of_helper_body' :: Arg r => (r -> a) -> (Reader r b) -> (b -> Reader r c) -> r -> a -> Proof
helper_of_helper_body' x y@(Reader _) g r2 r4  
  =   reader (\r3 -> fromReader (g ( (fromReader y) r3)) (r3)) 
  ==. bind y g 
  *** QED 



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