我正在按照本教程“Monad Transformers Step by Step”
进行操作http://www.cs.virginia.edu/~wh5a/personal/Transformers.pdf
和eval5中的代码功能来自第2.5节
type Name = String
data Exp = Lit Integer
| Var Name
| Plus Exp Exp
| Abs Name Exp
| App Exp Exp
deriving (Show)
data Value = IntVal Integer
| FunVal Env Name Exp
deriving (Show)
type Env = Map.Map Name Value
type Eval5 a = ReaderT Env (ErrorT String
(WriterT [String] (StateT Integer Identity))) a
runEval5 :: Env -> Integer -> Eval5 a -> ((Either String a, [String]), Integer)
runEval5 env st ev =
runIdentity (runStateT (runWriterT (runErrorT (runReaderT ev env))) st)
eval5 :: Exp -> Eval4 Value
eval5 (Lit i) = do tick
return $ IntVal i
eval5 (Var n) = do tick
tell [n]
env <- ask
case Map.lookup n env of
Nothing -> throwError("unbound variable: " ++ n)
Just val -> return val
eval5 (Plus e1 e2) = do tick
e1' <- eval5 e1
e2' <- eval5 e2
case (e1', e2') of
(IntVal i1, IntVal i2) ->
return $ IntVal $ i1 + i2
_ -> throwError "type error in Plus"
eval5 (Abs n e) = do tick
env <- ask
return $ FunVal env n e
eval5 (App e1 e2) = do tick
val1 <- eval5 e1
val2 <- eval5 e2
case val1 of
FunVal env' n body ->
local (const $ Map.insert n val2 env')
$ eval5 body
_ -> throwError "type error in App"
无法使用以下消息进行编译:
No instance for (MonadWriter [Name] Identity)
arising from a use of `tell'
Possible fix:
add an instance declaration for (MonadWriter [Name] Identity)
In a stmt of a 'do' block: tell [n]
In the expression:
do { tick;
tell [n];
env <- ask;
case Map.lookup n env of {
Nothing -> throwError ("unbound variable: " ++ n)
Just val -> return val } }
In an equation for `eval5':
eval5 (Var n)
= do { tick;
tell [n];
env <- ask;
.... }
ghc version 7.6.3
答案 0 :(得分:1)
假设tick
功能与论文中提到的功能相同:
tick :: Eval5 ()
tick = do n <- get
put (n+1)
在你的monad变换器中Eval4
与Eval5
之间似乎存在一些混淆。评估员似乎是针对Eval4
撰写的。这是固定来源:
import Control.Monad.Reader
import Control.Monad.Writer
import Control.Monad.Error
import Control.Monad.Identity
import Control.Monad.State
import qualified Data.Map as Map
type Name = String
data Exp = Lit Integer
| Var Name
| Plus Exp Exp
| Abs Name Exp
| App Exp Exp
deriving (Show)
data Value = IntVal Integer
| FunVal Env Name Exp
deriving (Show)
type Env = Map.Map Name Value
type Eval5 a = ReaderT Env (ErrorT String
(WriterT [String] (StateT Integer Identity))) a
runEval5 :: Env -> Integer -> Eval5 a -> ((Either String a, [String]), Integer)
runEval5 env st ev =
runIdentity (runStateT (runWriterT (runErrorT (runReaderT ev env))) st)
tick :: Eval5 ()
tick = do n <- get
put (n+1)
eval5 :: Exp -> Eval5 Value
eval5 (Lit i) = do
tick
return $ IntVal i
eval5 (Var n) = do
tick
tell [n]
env <- ask
case Map.lookup n env of
Nothing -> throwError("unbound variable: " ++ n)
Just val -> return val
eval5 (Plus e1 e2) = do
tick
e1' <- eval5 e1
e2' <- eval5 e2
case (e1', e2') of
(IntVal i1, IntVal i2) ->
return $ IntVal $ i1 + i2
_ -> throwError "type error in Plus"
eval5 (Abs n e) = do
tick
env <- ask
return $ FunVal env n e
eval5 (App e1 e2) = do
tick
val1 <- eval5 e1
val2 <- eval5 e2
case val1 of
FunVal env' n body ->
local (const $ Map.insert n val2 env')
$ eval5 body
_ -> throwError "type error in App"
在旁边有一个名为RWS(读/写器/状态)的复合monad变换器,它完全可以完成堆栈的功能。使用它可以简化展开代码。
type EvalRWST a = RWS Env [String] Integer a
runEvalRWS :: Env -> Integer -> EvalRWST a -> (a, Integer, [String])
runEvalRWS env st ev = runRWS ev env st