让我们考虑一下:
type Name = String -- variable names
data Exp = Lit Integer -- expressions
| Var Name
| Plus Exp Exp
| Abs Name Exp
| App Exp Exp
deriving (Show)
data Value = IntVal Integer -- values
| FunVal Env Name Exp
deriving (Show)
type Env = Map.Map Name Value -- mapping from names to values
eval0 :: Env -> Exp -> Value
eval0 env (Var n) = fromJust (Map.lookup n env )
以上是0版。
现在,让我们考虑monadic,1版本:
type Eval1 a = Identity a
eval1 :: Env -> Exp -> Eval1 Value
eval1 env (Var n) = Map.lookup n env
现在,作者说:
接下来是Var案例不再需要fromJust调用了: 原因是Map.lookup被定义为在任何monad中工作 简单地调用monad的失败函数 - 这非常适合我们的 这里的monadic公式。 (Maybe monad的失败功能 返回Nothing,而Identity monad中的fail函数 抛出异常,这将导致不同的错误消息。)
内容来自:http://www.cs.virginia.edu/~wh5a/personal/Transformers.pdf
我不清楚。请解释为什么引入monad Eval1允许我们不关心fromJust
。
编辑:
现在,我试图编译它并且我收到错误,这个错误与我的直觉和疑虑一致。编译器说:
Couldn't match type `Maybe Value' with `Identity Value'
Expected type: Eval1 Value
Actual type: Maybe Value
In the return type of a call of `Map.lookup'
In the expression: Map.lookup n env
In an equation for `eval1': eval1 env (Var n) = Map.lookup n env
那么,谁是对的,作者或编译者以及如何修复它?
答案 0 :(得分:6)
在撰写草稿时,Data.Map.lookup
显然与任何一个单子一起工作。这已不再适用,但作者确实提供了本教程的updated version。
具体而言,您必须检查生成的Maybe String
值并明确调用fail
。
-- Copied from the link above
eval1 env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env
答案 1 :(得分:2)
原因是Map.lookup被定义为只通过调用monad的失败函数在任何monad中工作
这不是真的。在文本中,Map.lookup
的定义与containers
包中的实际定义不同。作者将Map.lookup
概括为任何monadic值,而不仅仅是Maybe
:
lookup' :: (Ord k, Monad m) => k -> Map k a -> m a
lookup' k m = case Map.lookup k m of
Nothing -> fail "some_error_message"
Just v -> return v