packages feed

liquidhaskell-0.8.2.2: tests/pos/CountMonad.hs

{-@ LIQUID "--no-pattern-inline" @-}

module Count () where

{-@ measure count :: Count a -> Int @-}

{-@ Count :: x:a -> {v:Count a | v == Count x } @-}
data Count a = Count a 

instance Functor Count where
	fmap = undefined 
instance Applicative Count where
  pure  = undefined
  (<*>) = undefined	

instance Monad Count where
{-@
instance Monad Count where 
  >>=    :: forall <r :: Count a -> Bool, p :: Count b -> Bool, q :: Count b -> Bool>.
            {x::Count a <<r>>, y :: Count b <<p>>  |- {v:Count b | count v == count x + count y} <: Count b <<q>>} 
            Count a <<r>> -> (a -> Count b<<p>>) -> Count b <<q>> ; 
  >>     :: x:Count a -> y:Count b -> {v:Count b | count v == count x + count y}; 
  return :: a -> {v:Count a | count v == 0 } 
@-}
  return x        = let r = Count x in assertCount 0 (Count x)  
  (Count x) >>= f = let r = f x in assertCount (getCount (Count x) + getCount r) r 
  x >> y = assertCount (getCount x + getCount y) y
  fail          = error



{-@ assume assertCount :: i:Int -> x:Count a -> {v:Count a | v == x && count v == i } @-}
assertCount :: Int -> Count a -> Count a 
assertCount _ x = x 

{-@ assume getCount :: x:Count a -> {v:Int | v == count x } @-} 
getCount :: Count a -> Int 
getCount _ = 0 

{-@ makeCount :: x:a -> {v:Count a | v == Count x} @-}
makeCount = Count

{-@ assume incr :: a -> {v:Count a | count v == 1 } @-}
incr :: a -> Count a 
incr = Count 

{-@ assume unit :: {v:Count () | count v == 0 } @-}
unit = Count ()

{-@ foo :: a -> {v:Count a | count v == 0 }  @-}
foo :: a -> Count a 
foo y = return y  

{-@ test1 :: {v:Count () | count v == 0 } @-}
test1 :: Count ()
test1 = do 
  unit
  unit
  unit

{-@ test2 :: {v:Count () | count v == 1 } @-}
test2 = do 
  unit
  y <- incr ()
  unit
  foo y  
  unit

{-@ test3 :: {v:Count () | count v == 2 } @-}
test3 = do 
  unit
  unit
  incr ()
  incr ()
  unit