Let's consider:
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 )
And above is 0 version.
Now, let's consider monadic, 1 version:
type Eval1 a = Identity a
eval1 :: Env -> Exp -> Eval1 Value
eval1 env (Var n) = Map.lookup n env
And now, the author said:
The next is that the Var case does not need a fromJust call anymore: The reason is that Map.lookup is defined to work within any monad by simply calling the monad’s fail function – this fits nicely with our monadic formulation here. (The fail function of the Maybe monad returns Nothing, whereas the fail function in the Identity monad throws an exception, which will lead to different error messages.)
The content comes from: http://www.cs.virginia.edu/~wh5a/personal/Transformers.pdf
and it is not clear for me. Please explain why introducing monad Eval1 allow us to don't care about fromJust
.
EDIT:
Now, I tried to compile it and I got error and this error is consistent with my intuition and my doubts. The compiler says:
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
So, who is right, author or compiler and how to repair it?
At the time that draft was written, Data.Map.lookup
apparently did work with any monad. This is no longer true, but the author does provide an updated version of the tutorial.
Specifically, you have to examine the resulting Maybe String
value and call fail
explicitly.
-- Copied from the link above
eval1 env (Var n) = maybe (fail ("undefined variable: " ++ n)) return $ Map.lookup n env
The reason is that Map.lookup is defined to work within any monad by simply calling the monad's fail function
It's not true. In the text the definition of Map.lookup
is different from the real definition in containers
package. The author generalized Map.lookup
to any monadic value, not only 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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With