将 State monad 与 Either-style 错误传播相结合
Combining State monad with Either-style error propagation
我是 Haskell 的新手。我试图通过将 Either 视为 monad 来将 State monad 与错误传播结合起来。我想以不需要显式处理状态或错误的方式递归抽象语法树(例如,用于编写语句和表达式的解释器)。我的印象是,最简单的方法是使用 ExceptT monad 转换器。这是我编译的示例代码:
import Control.Monad.Except
import Control.Monad.State
import qualified Data.Map.Strict as M
-- simple expression language supporting crude let bindings
data Exp = Lit Int | Var String
| Add (Exp, Exp) | Let (String, Exp, Exp) deriving Show
okExp = -- let x = 2 in let y = x + 3 in x + y -- evaluate to 7
Let ("x", Lit 2,
Let ("y", Add (Var "x", Lit 3),
Add (Var "x", Var "y")))
badExp = Var "x" -- error: x is not defined
type St = M.Map String Int
initialState :: St
initialState = M.empty
type EvalMonad = ExceptT String (State St)
evalExp :: Exp -> EvalMonad Int
evalExp (Lit n) = return n
evalExp (Var v) = do
mp <- lift get
case M.lookup v mp of
Just i -> return i
Nothing -> throwError (v ++ " not found")
evalExp (Add (a, b)) = do
x <- evalExp a
y <- evalExp b
return (x + y)
我希望 运行 对简单示例(例如 okExp、badExp)进行 evalExp。我不确定三件事:
- 如何将初始状态纳入计算?
- 如何使用 运行ExceptT 提取结果?
- (更一般):这是解决这个问题的 "right" 方法吗?
看起来是个不错的开始!这是一个小例子,展示了如何在 ghci 中一起使用 runExceptT
和 runState
:
> runState (runExceptT (evalExp (Add (Lit 3, Lit 4)))) initialState
(Right 7,fromList [])
> runState (runExceptT (evalExp (Add (Lit 3, Var "x")))) initialState
(Left "x not found",fromList [])
我是 Haskell 的新手。我试图通过将 Either 视为 monad 来将 State monad 与错误传播结合起来。我想以不需要显式处理状态或错误的方式递归抽象语法树(例如,用于编写语句和表达式的解释器)。我的印象是,最简单的方法是使用 ExceptT monad 转换器。这是我编译的示例代码:
import Control.Monad.Except
import Control.Monad.State
import qualified Data.Map.Strict as M
-- simple expression language supporting crude let bindings
data Exp = Lit Int | Var String
| Add (Exp, Exp) | Let (String, Exp, Exp) deriving Show
okExp = -- let x = 2 in let y = x + 3 in x + y -- evaluate to 7
Let ("x", Lit 2,
Let ("y", Add (Var "x", Lit 3),
Add (Var "x", Var "y")))
badExp = Var "x" -- error: x is not defined
type St = M.Map String Int
initialState :: St
initialState = M.empty
type EvalMonad = ExceptT String (State St)
evalExp :: Exp -> EvalMonad Int
evalExp (Lit n) = return n
evalExp (Var v) = do
mp <- lift get
case M.lookup v mp of
Just i -> return i
Nothing -> throwError (v ++ " not found")
evalExp (Add (a, b)) = do
x <- evalExp a
y <- evalExp b
return (x + y)
我希望 运行 对简单示例(例如 okExp、badExp)进行 evalExp。我不确定三件事:
- 如何将初始状态纳入计算?
- 如何使用 运行ExceptT 提取结果?
- (更一般):这是解决这个问题的 "right" 方法吗?
看起来是个不错的开始!这是一个小例子,展示了如何在 ghci 中一起使用 runExceptT
和 runState
:
> runState (runExceptT (evalExp (Add (Lit 3, Lit 4)))) initialState
(Right 7,fromList [])
> runState (runExceptT (evalExp (Add (Lit 3, Var "x")))) initialState
(Left "x not found",fromList [])