Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monad Transformers. First step

Tags:

haskell

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?

like image 524
Gilgamesz Avatar asked Apr 10 '16 12:04

Gilgamesz


2 Answers

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
like image 195
chepner Avatar answered Sep 28 '22 11:09

chepner


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
like image 24
zakyggaps Avatar answered Sep 28 '22 10:09

zakyggaps