Map.lookup is defined to work within any monad [duplicate] - haskell

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.

Related

Monad Transformers in an Interpeter

I am encountering a problem with Monad Transformers, but I think it's helpful to include some context of how I got to the state I'm currently in, so I'll start with a rough explanation of my program:
The project is an interpreter for a simple (toy) programming language. I have a monad that is used to represent evaluation. It has a definition that looks like:
type Eval a = ReaderT Environment (ExceptT String (State ProgState a))
This works quite nicely, and I can happy write an evaluation function:
eval :: Expr -> Eval Value
eval (Apply l r) = ...
eval ...
The Value datatype has a slight quirk in that I embed Haskell functions of type Value -> EvalM Value. To do this I added a generic type parameter to the definition, which I then instantiate with EvalM:
data Value' m
= IntVal Int
...
| Builtin (Value' m -> m (Value' m))
type Value = Value' EvalM
Things were going well, but then I had to write a function that heavily interleaved code using the Eval monad with IO operations. This looked kinda horrendous:
case runEval ({-- some computation--}) of
Right (val, state') -> do
result <- -- IO stuff here
case runEvaL {-- something involving result --} of
...
Left err -> ...
The function had like 5 levels of nesting, and was also recursive... definitely ugly :(. I hoped adapting to use a Monad Transformer would be the solution:
type EvalT m = ReaderT Environment (ExceptT String (StateT ProgState m))
This refactor was relatively painless: mostly it involved changing type-signatures rather than actual code, however there was a problem: Builtin. Given a expression that was applying argument x to a value of the form Builtin f, the eval function would simply return f x. However, this has type Eval Value, but the refactored eval needs to have type-signature:
eval :: Monad m => EvalT m Value
As far as Fixing this (i.e. making it typecheck) is concerned, I can think of a couple solutions each of which has a problem:
Implementing some kind of analog to lift where I can take Eval a to EvalT m a.
Problem: I'm not aware of how to do this (or if it's even possible)
Changing the Value type so that it is indexed by an inner monad, i.e. Value m = Value' (EvalT m).
Problem: now anything containing a Value m has to be
parameterized by m. I feel that it would unnecessarily clutters up the type-signatures of
anything containing a Value, which is a problem given the initial
motivation to do this change was cleaning up my code.
Of course, there may be a much better solution that I haven't thought of yet. Any feedback/suggestions are appreciated :).
You might like the mmorph package.
-- since State s = StateT s Identity, it's probably also the case
-- that Eval = EvalT Identity, under some light assumptions about
-- typos in the question
liftBuiltin :: Monad m => Eval a -> EvalT m a
liftBuiltin = hoist (hoist (hoist generalize))
Alternately, you could store a polymorphic function in your value. One way would be to parameterize over the transformer.
data Value' t = ... | Builtin (forall m. Monad m => Value' t -> t m (Value' t)
type Value = Value' EvalT
Another is to use mtl-style constraints.
data Value = ... | Builtin (forall m. (MonadReader Environment m, MonadError String m, MonadState ProgState m) => Value -> m Value)
This last one, though verbose, looks pretty nice to me; I'd probably start there.

How does an environment happen to be a partially applied function, and even a hom functor?

I have seen Reader being used to major benefit many times in the wild. (One notable example would be stack, built around a straightforward derivative of Reader that can inform the user of the sufficiency of its contents on the type level.) After some thinking, I arrived to an understanding that this benefit is merely on the level of code structure, and, in a sense, all that Reader does is supply a parameter, in many places, to a complicated wiring of functions. That is, I came to believe we can always replace a reader that holds some x with a lambda abstraction of form λx. ... x ... x .... This seems to align with the official explanations that claim:
... the partially applied function type (->) r is a simple reader monad ...
However, there is a long way from noting that Reader is a way to write down a lambda abstraction piecewise, to claiming that it is a partially applied function.
Is there a function that is applied, but not partially? It would simply be a value:
λ :t id 1
id 1 :: Num a => a
λ :t 1
1 :: Num a => a
Is there a function that is not even partially applied? We'll never know:
λ :t fromMaybe
fromMaybe :: a -> Maybe a -> a
λ :t flip maybe id
flip maybe id :: b -> Maybe b -> b
Even ignoring this as nitpicking, I would not take on faith that (->) r (why not just write (r ->)?) is exactly and singularly a Reader monad. Maybe I could write an instance that typechecks. Maybe it would even obey the laws. As long as I do not think of my functions as Readers, as long as I do not have the right intuition, the vision of it, it is as useful to me as the first proof of the Four Colour Theorem. On the other hand, how can I be sure this is the only way of defining a monad on functions? There are several Monoids on Num, at least two Applicatives on Lists − would it not be too reckless to consider a function a Reader monad alone?
The predicament does not end here. Once I go searching for an answer, I stumble upon an even more puzzling note: Reader happens to be the hom functor now, or even a representable functor in general. And the folks from the other end of the spectrum actually know ahead of time that there would be such a construct in Haskell, and even spell its type, the same as it is spelled in the aforementioned official explanations. Now, this is way over my head, but I can parse the definition of hom functor from Mac Lane. With some imagination, it can be seen that, granted a function a -> b as a morphism in the (supposed) category Hask, we may compose it with id to obtain... a function a -> b again, this time as an element of the set hom(a, b).
Does this connect in any way with some of these morphisms being partially applied? Or with the use of Reader as option store in stack? Can I actually be shown the object and arrow functions of the hom functor Hask -> Set? (I shall take an endofunctor Hask -> Hask as a reasonable approximation.) Would that be my trusty fellows pure and fmap?
And, well, how do I actually use Reader, after that?
I can't answer all of your questions, but let's start with the easy ones:
(->) r (why not just write (r ->)?)
Because the latter is a syntax error in Haskell. You can't use this section syntax on types.
... claiming that it is a partially applied function.
That's not what it's saying. The quote is:
the partially applied function type (->) r is a simple reader monad
It's a partially applied type, not a partially applied function. Or in other words, it's parsed like this: ((partially applied) (function type))
The type constructor for function types in Haskell is spelled ->.
A fully applied function type looks like r -> a (or equivalently (->) r a), where r is the argument type and a the result type.
Thus (->) r is a partial application of -> (the function type).
If we ignore monad transformers and ReaderT, the straightforward definition of Reader is:
newtype Reader r a = Reader (r -> a)
runReader :: Reader r a -> r -> a
runReader (Reader f) x = f x
-- or rather:
runReader :: Reader r a -> (r -> a)
runReader (Reader f) = f
or equivalently:
newtype Reader r a = Reader{ runReader :: r -> a }
That is, Reader is just a newtype for -> (a very thin wrapper), with runReader for unwrapping.
You can even make -> an instance of MonadReader just by copying the instance for Reader and removing all the Reader / runReader wrapping/unwrapping.

The Maybe result from Map.lookup is not type checking with my Monad Transformer stack

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.

Use MonadRef to implement MonadCont

There is a well known issue that we cannot use forall types in the Cont return type.
However it should be OK to have the following definition:
class Monad m => MonadCont' m where
callCC' :: ((a -> forall b. m b) -> m a) -> m a
shift :: (forall r.(a -> m r) -> m r) -> m a
reset :: m a -> m a
and then find an instance that makes sense. In this paper the author claimed that we can implement MonadFix on top of ContT r m providing that m implemented MonadFix and MonadRef. But I think if we do have a MonadRef we can actually implement callCC' above like the following:
--satisfy law: mzero >>= f === mzero
class Monad m => MonadZero m where
mzero :: m a
instance (MonadZero m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef Nothing
v <- k (\a -> writeRef ref (Just a) >> mzero)
r <- readRef ref
return $ maybe v id r
shift = ...
reset = ...
(Unfortunately I am not familiar with the semantic of shift and reset so I didn't provide implementations for them)
This implementation seems OK for me. Intuitively, when callCC' being called, we feed k which a function that its own effect is always fail (although we are not able to provide a value of arbitrary type b, but we can always provide mzero of type m b and according to the law it should effectively stop all further effects being computed), and it captures the received value as the final result of callCC'.
So my question is:
Is this implementation works as expected for an ideal callCC? Can we implement shift and reset with proper semantic as well?
In addition to the above, I want to know:
To ensure the proper behaviour we have to assume some property of MonadRef. So what would the laws a MonadRef to have in order to make the above implementation behave as expected?
UPDATE
It turn out that the above naive implementation is not good enough. To make it satisfy "Continuation current"
callCC $\k -> k m === callCC $ const m === m
We have to adjust the implementation to
instance (MonadPlus m, MonadRef r m) => MonadCont' m where
callCC' k = do
ref <- newRef mzero
mplus (k $ \a -> writeRef ref (return a) >> mzero) (join (readRef ref))
In other words, the original MonadZero is not enough, we have to be able to combind a mzero value with a normal computation without cancelling the whole computation.
The above does not answer the question, it is just adjusted as the original attempt was falsified to be a candidate. But for the updated version, the original questions are still questions. Especially, reset and shift are still up to be implemented.
(This is not yet an answer, but only some clues came up in my mind. I hope this will lead to the real answer, by myself or by someone else.)
Call-by-Value is Dual to Call-by-Name -- Philip Wadler
In the above paper the author introduced the "Dual Calculus", a typed calculus that is corresponding to the classical logic. In the last section, there is a segment says
A strategy dual to call-by-need could
avoid this inefficiency by overwriting a coterm with its covalue
the first time it is evaluated.
As stated in Wadler's paper, call-by-name evaluating the continuations eagerly (it returns before all values being evaluated) whilst call-by-value evaluating the continuations lazily (it only returns after all values being evaluated).
Now, take a look at the callCC' above, I believe this is an example of the dual of call-by-need in the continuation side. The strategy of the evaluation, is that provide a fake "continuation" to the function given, but cache the state at this point to call the "true" continuation later on. This is somehow like making a cache of the continuation, and so once the computation finishes we restore that continuation. But cache the evaluated value is what it mean by call-by-need.
In general I suspect, state (computation up to the current point of time) is dual to continuation (the future computation). This will explain a few phenomenons. If this is true, it is not a surprise that MonadRef (correspond to a global and polymorphic state) is dual to MoncadCont (correspond to global and polymorphic continuations), and so they can be used to implement each other.

Converting monads

Lets say I have function
(>>*=) :: (Show e') => Either e' a -> (a -> Either e b) -> Either e b
which is converting errors of different types in clean streamlined functions. I am pretty happy about this.
BUT
Could there possibly be function <*- that would do similar job insted of <- keyword, that it would not look too disturbing?
Well, my answer is really the same as Toxaris' suggestion of a foo :: Either e a -> Either e' a function, but I'll try to motivate it a bit more.
A function like foo is what we call a monad morphism: a natural transformation from one monad into another one. You can informally think of this as a function that sends any action in the source monad (irrespective of result type) to a "sensible" counterpart in the target monad. (The "sensible" bit is where it gets mathy, so I'll skip those details...)
Monad morphisms are a more fundamental concept here than your suggested >>*= function for handling this sort of situation in Haskell. Your >>*= is well-behaved if it's equivalent to the following:
(>>*=) :: Monad m => n a -> (a -> m b) -> m b
na >>*= k = morph na >>= k
where
-- Must be a monad morphism:
morph :: n a -> m a
morph = ...
So it's best to factor your >>*= out into >>= and case-specific monad morphisms. If you read the link from above, and the tutorial for the mmorph library, you'll see examples of generic utility functions that use user-supplied monad morphisms to "edit" monad transformer stacks—for example, use a monad morphism morph :: Error e a -> Error e' a to convert StateT s (ErrorT e IO) a into StateT s (ErrorT e' IO) a.
It is not possible to write a function that you can use instead of the <- in do notation. The reason is that to the left of <-, there is a pattern, but functions take values. But maybe you can write a function
foo :: (Show e') => Either e' a -> Either e a
that converts the error messages and then use it like this:
do x <- foo $ code that creates e1 errors
y <- foo $ code that creates e2 errors
While this is not as good as the <*- you're asking for, it should allow you to use do notation.

Resources