pisigma-0.1.0.2: src/PiSigma/Evaluation.hs
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module PiSigma.Evaluation where
import Control.Monad.Error
import Control.Monad.State
import Control.Monad.Identity
import PiSigma.Syntax
-- * Monad used for evaluation
newtype Eval e a =
Eval {unEval :: StateT e (ErrorT String Identity) a}
deriving (Monad,MonadError String,MonadState e)
run :: e -> Eval e a -> Either String (a,e)
run e (Eval p) = runIdentity $ runErrorT $ runStateT p e
catchE :: Eval e a -> (String -> Eval e a) -> Eval e a
catchE = catchError
getEnv :: Eval e e
getEnv = get
setEnv :: e -> Eval e ()
setEnv = put
getId :: Name -> Scope -> Eval e Id
getId x s = case lookupScope s x of
Just i -> return i
Nothing -> fail ("Undefined Variable: "++x++"\n")
-- | Takes a name, a scope, and potentially a type.
-- It extends the environment and the scope with that name.
decl :: Env e =>
Name -> PrtInfo -> Scope -> Maybe (Clos Type) ->
Eval e (Id,Scope)
decl x x' s a =
do e <- getEnv
let (i,e') = extE e x'
setEnv e'
return (i,extendScope s x (i,a))
decl' :: Env e => Name -> Scope -> Eval e (Id,Scope)
decl' x s = decl x (PrtInfo {name = x, expand = True}) s Nothing
tdecl :: Env e => Name -> Scope -> (Clos Type) -> Eval e (Id,Scope)
tdecl x g a = decl x (PrtInfo {name = x, expand = True}) g (Just a)
-- | Updates the environment.
defn :: Env e => Id -> EnvEntry -> Eval e ()
defn i ei =
do e <- getEnv
setEnv (setE e i ei)
defn' :: Env e => Id -> Clos Type -> Eval e ()
defn' i t = defn i (Closure t)
-- | Locally updates the environment.
letn :: Env e => Id -> EnvEntry -> Eval e a -> Eval e a
letn i ei p =
do eo <- lookupId i
defn i ei
a <- p
defn i eo
return a
letn' :: Env e => Id -> Clos Type -> Eval e a -> Eval e a
letn' i t p = letn i (Closure t) p
subst :: Env e => Bind (Clos Term) -> (Clos Term) -> Eval e (Clos Term)
subst (x,(t,s)) u =
do (i,s') <- decl' x s
defn' i u
return (t,s')
evalApp :: Env e => Val -> (Clos Term) -> Eval e Val
evalApp (VLam xt) u = subst xt u >>= eval
evalApp (Ne t) u = return (Ne (t :.. u))
evalApp _ _ = fail "function expected"
lookupId :: Env e => Id -> Eval e EnvEntry
lookupId i = liftM (flip getE i) getEnv
evalId :: Env e => Id -> Eval e Val
evalId i =
do ei <- lookupId i
case ei of
Closure t -> eval t
Id j -> return (Ne (NVar j))
-- use subst!
evalSplit :: Env e => Val -> (Bind (Bind (Clos Term))) ->
Eval e Val
evalSplit (VPair ((l,r),s)) (x,(y,(t,s'))) =
do (x',s2) <- decl' x s'
(y',s3) <- decl' y s2
defn' x' (l,s)
defn' y' (r,s)
eval (t,s3)
evalSplit (Ne n) (xy,t) = return (Ne (NSplit n (xy,t)))
evalSplit _ _ = fail "Pair expected"
evalCase :: Env e => Val -> Clos [(Label,Term)] -> Eval e Val
evalCase (VLabel l) (lts,s) =
case lookup l lts of
Nothing -> fail "case not matched"
Just t -> eval (t,s)
evalCase (Ne n) lts = return (Ne (NCase n lts))
evalCase _ _ = fail "Label expected"
force :: Env e => Val -> Eval e Val
force (VBox (Boxed c)) = eval c
force (Ne n) = return (Ne (NForce n))
force _ = fail "Box expected"
eval :: Env e => (Clos Term) -> Eval e Val
eval (Var x, s) = getId x s >>= evalId
eval (Let g t, s) = evalProg (g,s) >>= curry eval t
eval (Type,s) = return VType
eval (Q ps axb,s) = return (VQ ps (axb,s))
eval (Lift t,s) = return (VLift (t,s))
eval (Lam (x,t), s) = return (VLam (x,(t,s)))
eval (t :. u ,s) = eval (t,s) >>= flip evalApp (u,s)
eval (Pair tu,s) = return (VPair (tu,s))
eval (Split t (x,(y,u)),s)
= eval (t,s) >>= flip evalSplit (x,(y,(u,s)))
eval (Enum ls,s) = return (VEnum ls)
eval (Label l,s) = return (VLabel l)
eval (Case t lts,s) = eval (t,s) >>= flip evalCase (lts,s)
eval (Box t,s) = return (VBox (Boxed (t,s)))
eval (Force t,s) = eval (t,s) >>= force
-- forced eval (should be integrated into eval?)
feval :: Env e => (Clos Term) -> Eval e Val
feval t = do t' <- eval t
case t' of
VBox (Boxed u) -> feval u
v -> return v
evalProg :: Env e => Clos Prog -> Eval e Scope
evalProg ([],s) = return s
evalProg ((Decl x _):tel, s) = do (_,s') <- decl x (PrtInfo x False) s Nothing
evalProg (tel,s')
evalProg ((Defn x t):tel, s) = do i <- getId x s
defn' i (t,s)
evalProg (tel,s)