Monad变形金刚。第一步

时间:2016-04-10 12:03:31

标签: haskell

让我们考虑一下:

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

那么,谁是对的,作者或编译者以及如何修复它?

2 个答案:

答案 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