packages feed

liquidhaskell-0.8.10.7: tests/ple/pos/MJFix.hs

-- | This tests that we dig up sorts (for `applySorts`) from the BODIES of reflected functions.
-- c.f. https://piazza.com/class/jqk23zupq7a62c?cid=72

{-@ LIQUID "--reflection"  @-}
{-@ LIQUID "--ple"         @-}  -- Bug goes away if this line is commented
{-@ LIQUID "--short-names" @-}

module Test where

import Prelude hiding ((++), const, sum, init)

data GState k v = Init v | Bind k v (GState k v) 

type Proof = ()

{-@ reflect init @-}
init :: v -> GState k v
init v = Init v  

{-@ reflect set @-}
set :: GState k v -> k -> v -> GState k v
set s k v = Bind k v s 

{-@ reflect get @-}
get :: (Eq k) => GState k v -> k -> v
get (Init v)     _   = v
get (Bind k v s) key = if key == k then v else get s key

------------------------------------------------------------------------------
-- | Arithmetic Expressions
------------------------------------------------------------------------------

type Vname = String

data AExp
  = N Val
  | V Vname
  | Plus AExp AExp
  deriving (Show)

type Val   = Int
type State = GState Vname Val

{-@ reflect aval @-}
aval                :: AExp -> State -> Val
aval (N n) _        = n
aval (V x) s        = get s x
aval (Plus e1 e2) s = aval e1 s + aval e2 s

data LExp
  = LN    Int                 -- ^ Numbers
  | LV    Vname               -- ^ Variables
  | LPlus LExp  LExp          -- ^ Addition
  | LLet  Vname LExp LExp     -- ^ Let binding
  deriving (Show)

-- | `lval l s` takes a let-bound expression and a State and returns the result
--    of evaluating `l` in `s`:

{-@ reflect lval @-}
lval :: LExp -> State -> Int
lval (LN i) _         = i
lval (LV x) s         = get s x
lval (LPlus e1 e2)  s = lval e1 s + lval e2 s
lval (LLet x e1 e2) s = lval e2 (set s x (lval e1 s))

-- | Write a function `inlyne` that converts an `LExp` into a plain `AExp`
--   by "inlining" the let-definitions, i.e. `let x = e1 in e2` should become
--     e2-with-all-occurrences-x-replaced-by-e1

{-@ reflect inlyne @-}
inlyne :: LExp -> AExp
inlyne lexp = replace lexp (init (N 0))


-- NIKI TO FIX
-- The below is required because the sort `GState Int AExp`
-- does not appear in the logic, so apply :: Int -> GState Int AExp
-- was not generated
{-@ reflect help @-}
help :: GState Int AExp
help = init (N 0)

{-@ reflect contains @-}
contains :: (Eq k) => GState k v -> k -> Bool
contains (Bind k v kvs) key
  | key == k   = True
  | otherwise  = contains kvs key
contains _ _  = False

{-@ reflect replace@-}
replace :: LExp -> GState Vname AExp -> AExp
replace (LN i) _ = (N i)
replace (LV x) s = if s `contains` x then get s x else (V x)
replace (LPlus l r) s = Plus (replace l s) (replace r s)
replace (LLet x e1 e2) s = let
  newS = set s x (replace e1 s)
  in
    replace e2 newS

-- Bug also goes away if the below liquid line is commented out.
{-@ lem_inlyne :: l:_ -> s:_ -> { lval l s = aval (inlyne l) s } @-}
lem_inlyne :: LExp -> State -> Proof
lem_inlyne = undefined -- impossible "TODO"