I am going though the following paper: Monad Transformers Step by Step. In section 2.1 "Converting to Monadic Style", a function is converted to return Value
in the Eval1
monad. This part of the function doesn't make sense to me:
eval1 env (Var n) = Map.lookup n env
The result of that will be Maybe Value
however the function's type signature is:
eval1 :: Env → Exp → Eval1 Value
The function is failing to type check, and the error seems obvious to me. Yet the author specifically states that this will work:
... 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 signature for Map.lookup does not look like it is designed to work with any monad:
lookup :: Ord k => k -> Map k a -> Maybe a
Is this paper out of date or am I missing something? If the paper is in fact out of date, why was lookup
changed to only work with Maybe
.
Thanks!
Your tutorial is from 2006. It uses a very old version of Data.Map
in which lookup
's type indeed was:
lookup :: (Monad m, Ord k) => k -> Map k a -> m a
I reckon the change happened because fail
is widely considered to be a wart in the Monad
class. Returning a Maybe a
makes a lookup failure explicit and manageable. Making it implicit by hiding it behind fail
just to have a slightly more convenient type is quite dirty IMO. (See also the question linked to by Ørjan.)
You can use this adapted version of lookup
to follow along the tutorial:
fallibleLookup :: (Ord k, Monad m) => k -> Map.Map k a -> m a
fallibleLookup k = maybe (fail "fallibleLookup: Key not found") pure . Map.lookup k
Note that with the upcoming release of GHC 8.8 the proper constraint to use on m
will be MonadFail
rather than Monad
.
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