module InterpC where -- The interpreter monad -- (Generated by MonadLab) import InterpMonadC -- Language syntax type Name = String data Term = Var Name | Con Int | Add Term Term | Lam Name Term | App Term Term | LetRef Name Term Term | Deref Term | PutRef Term Term | Seq Term Term | Print Term instance Show V where show Wrong = "Wrong" show (Num n) = show n show (Fun _) = "" show (Ref _) = "" show Unit = "Unit" mkfun :: Name -> M V -> M V mkfun x phi = rdEnvM >>= \ e -> return (Fun $ \ arg -> inEnvM ((x,arg):e) phi) appEnv :: Name -> M V appEnv x = rdEnvM >>= \ e -> case lookup x e of Nothing -> return Wrong (Just v) -> return v getLoc :: Loc -> M V getLoc l = getStoM >>= \s -> case lookup l s of Nothing -> return Wrong (Just v) -> return v putLoc :: Loc -> V -> M () putLoc l v = getStoM >>= \s -> putStoM $ (l,v):s findFreeLoc :: M Loc findFreeLoc = getStoM >>= \s -> return (ffl 0 s) -- This is clearly inefficient, but it gets the idea across. where ffl :: Loc -> Store -> Loc ffl n sto = case lookup n sto of Nothing -> n _ -> ffl (n+1) sto inExtEnvRef :: Name -> V -> M V -> M V inExtEnvRef x v phi = findFreeLoc >>= \l -> putLoc l v >> rdEnvM >>= \ e -> inEnvM ((x,(Ref l)):e) phi apply :: V -> V -> M V apply (Fun k) a = k a apply _ _ = return Wrong -- The interpreter add :: V -> V -> M V add (Num i) (Num j) = return (Num (i+j)) add _ _ = return Wrong interp :: Term -> M V interp (Var x) = appEnv x interp (Con i) = return (Num i) interp (Add u v) = interp u >>= \ a -> interp v >>= \ b -> add a b interp (Lam x v) = mkfun x (interp v) interp (App t u) = interp t >>= \ f -> interp u >>= \ a -> apply f a interp (LetRef x v t) = interp v >>= \val -> inExtEnvRef x val (interp t) interp (Deref t) = interp t >>= \ref -> case ref of (Ref l) -> getLoc l _ -> return Wrong interp (PutRef r v) = interp r >>= \ref -> case ref of (Ref l) -> interp v >>= putLoc l >> return Unit _ -> return Wrong interp (Seq t1 t2) = interp t1 >> interp t2 interp (Print t) = interp t >>= \ v -> tellOutM (show v) >> return Unit test :: Term -> (V,String) test t = runM (listenOutM $ interp t) initEnv initSto where initEnv = [] initSto = []