packages feed

liquidhaskell-0.8.10.7: benchmarks/popl18/nople/todo/Soundness.hs

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

module Soundness where

import Prelude hiding (Maybe(..))
import Proves


data Maybe a = Nothing | Just a
  deriving (Show, Eq)

{-@ data Maybe a =
      Nothing
     | Just {select_Just_1 :: a} @-}

{-@ measure is_Nothing @-}
is_Nothing Nothing = True
is_Nothing _       = False

{-@ measure is_Just @-}
is_Just (Just _) = True
is_Just _        = False

-- | Data Types

data Type =
    TBool
  | TFun { tFunArg :: Type, tFunRes :: Type }
  deriving (Eq, Show)

{-@
data Type [tsize] =
    TBool
  | TFun { tFunArg :: Type, tFunRes :: Type }
@-}


data Expr =
    EVar { eVarVal :: Int }
  | EApp { eAppArg :: Expr , eAppRes :: Expr }
  | EAbs { eAbsVar :: Int, eAbsType :: Type, eAbsBody :: Expr }
  | ETrue
  | EFalse
  | EIf  { eIfCond :: Expr, eIfTrue :: Expr, eIfFalse :: Expr }
  deriving (Eq, Show)

{-@
data Expr [esize] =
    EVar { select_EVar_1 :: Int }
  | EApp { select_EApp_1 :: Expr , select_EApp_2 :: Expr }
  | EAbs { select_EAbs_1 :: Int,   select_EAbs_2 :: Type, select_EAbs_3 :: Expr }
  | ETrue
  | EFalse
  | EIf  { select_EIf_1 :: Expr, select_EIf_2 :: Expr, select_EIf_3 :: Expr }

@-}


{-@ measure is_EVar @-}
is_EVar (EVar _) = True
is_EVar _        = False

{-@ measure is_EApp @-}
is_EApp (EApp _ _) = True
is_EApp _          = False

{-@ measure is_EAbs @-}
is_EAbs (EAbs _ _ _) = True
is_EAbs _            = False

{-@ measure is_ETrue @-}
is_ETrue ETrue = True
is_ETrue _     = False

{-@ measure is_EFalse @-}
is_EFalse EFalse = True
is_EFalse _      = False

{-@ measure is_EIf @-}
is_EIf (EIf _ _ _) = True
is_EIf _            = False

{-@ measure esize @-}

{-@ invariant {v:Expr | 0 <= esize v } @-}
-- | Auto generated invariants does not work,
-- | see https://github.com/ucsd-progsys/liquidhaskell/issues/723

esize :: Expr -> Int
esize ETrue         = 0
esize EFalse        = 0
esize (EVar _)      = 1
esize (EApp e1 e2)  = 1 + esize e1 + esize e2
esize (EAbs _ _ e)  = 1 + esize e
esize (EIf c e1 e2) = 1 + esize c + esize e1 + esize e2

-- | Operational Semantics
{-@ measure isValue @-}
isValue :: Expr -> Bool
isValue (EAbs _ _ _) = True
isValue ETrue        = True
isValue EFalse       = True
isValue _            = False

{-@ axiomatize subst @-}
{-@ subst :: Int -> Expr -> e:Expr -> Expr / [esize e] @-}
subst x ex (EVar y)     | x == y
  = ex
subst x ex (EAbs y t e) | x /= y
  = EAbs y t (subst x ex e)
subst x ex (EApp e1 e2)
  = EApp (subst x ex e1) (subst x ex e2)
subst x ex (EIf c e1 e2)
  = EIf (subst x ex c) (subst x ex e1) (subst x ex e2)
subst x ex e
  = e


{-@ axiomatize step @-}
step :: Expr -> Maybe Expr
step (EApp e1 e2)
  = if isValue e1 then
       if isValue e2 then
          case e1 of
            EAbs x _ ex -> Just (subst x ex e2)
            _           -> Nothing
       else
           case step e2 of
             Just e2' -> Just (EApp e1 e2')
             _        -> Nothing
    else case step e1 of
           Just e1' -> Just (EApp e1' e2)
           _        -> Nothing
step (EIf c e1 e2)
  = if isValue c then
      case c of
        ETrue  -> Just e1
        EFalse -> Just e2
        _      -> Nothing
    else case step c of
          Just c' -> Just (EIf c' e1 e2)
          Nothing -> Nothing
step _
  = Nothing


test1 = step (EApp (EAbs 0 TBool (EVar 0)) ETrue) == Just ETrue
test2 = step (EApp ETrue ETrue) == Nothing


-- | Type Checker

type Env = Int -> Maybe Type
{-@ axiomatize empty  @-}
empty :: Env
empty _ = Nothing

extend :: Env -> Int -> Type -> Env
extend γ x t x' = if x == x' then Just t else γ x'

{-@ measure typing :: Env -> Expr -> Maybe Type @-}
typing :: Env -> Expr -> Maybe Type
typing γ (EVar x)
  = γ x
typing γ (EAbs x tx e)
  = case typing (extend γ x tx) e of
      Just t  -> Just $ TFun tx t
      Nothing -> Nothing
typing _ ETrue
  = Just TBool
typing _ EFalse
  = Just TBool
typing γ (EIf c e1 e2)
  = case (typing γ c, typing γ e1, typing γ e2) of
      (Just TBool, Just t1, Just t2) -> if t1 == t2 then Just t1 else Nothing
      _                              -> Nothing
typing γ (EApp e1 e2)
  = case (typing γ e1, typing γ e2) of
      (Just (TFun t11 t12), Just t2) -> if t11 == t2 then Just t12 else Nothing
      _                              -> Nothing



bar :: Eq b =>  Maybe b -> Proof
{-@ bar :: m:Maybe b -> {m == Nothing => not (is_Just m) } @-}
bar Nothing
  = is_Just Nothing ==. False ==. not True *** QED
bar (Just x) = simpleProof

foo :: Int -> Proof
{-@ foo :: v:Int -> { not (is_Just (typing empty (EVar v))) } @-}
foo v
  =   is_Just (typing empty (EVar v))
  ==. is_Just (empty v)
  ==. is_Just ((\_-> Nothing) v)
  ==. is_Just Nothing          ? bar (typing empty (EVar v))
  *** QED

-- | Soundness proofs
progress :: Expr -> Proof
{-@ progress :: e:{Expr | is_Just (typing empty e)}
             -> {isValue e || is_Just (step e)}
  @-}

progress (EVar x)
  = foo x
{-
typing γ (EAbs x tx e)
  = case typing (extend γ x tx) e of
      Just t  -> Just $ TFun tx t
      Nothing -> Nothing
typing _ ETrue
  = Just TBool
typing _ EFalse
  = Just TBool
typing γ (EIf c e1 e2)
  = case (typing γ c, typing γ e1, typing γ e2) of
      (Just TBool, Just t1, Just t2) -> if t1 == t2 then Just t1 else Nothing
      _                              -> Nothing
typing γ (EApp e1 e2)
  = case (typing γ e1, typing γ e2) of
      (Just (TFun t11 t12), Just t2) -> if t11 == t2 then Just t12 else Nothing
      _                              -> Nothing
-}
progress e
   = undefined