Correctness of implicit lifting - haskell

Imagine that I have a value that is generic over the monad:
m :: (Monad m) => m A -- 'A' is some concrete type
Now let's say that I specialize this value to a concrete monad transformer stack in two separate ways:
m1 :: T M A
m1 = m
m2 :: T M A
m2 = lift m
... where M and T M are monads, and T is a monad transformer:
instance Monad M where ...
instance (Monad m) => Monad (T m) where ...
instance MonadTrans T where ...
... and those instances obey the monad laws and monad transformer laws.
Can we deduce that:
m1 = m2
... knowing nothing about m other than its type?
This is just a long-winded way of asking if lift m is a valid substitution for m, assuming that both type-check. It is a little bit difficult to phrase the question because it requires m type-checking as two separate monads before and after the substitution. As far as I can tell, the only way such a substitution would type-check is if m is generic over the monad.
My vague intuition is that the substitution should always be correct, but I'm not sure that my intuition is correct, or how to prove it if it is correct.

If m :: Monad m => m A, then m must be equivalent to return x for some x :: A, because the only ways you have to get anything :: m x are return and (>>=). But in order to use (>>=) you must be able to produce some m y, which you can either do with return or with another application of (>>=). Either way you have to use return eventually, and the monad laws guarantee that the whole expression will be equivalent to return x.
(If m is completely polymorphic over the monad, then you must able to use it at m ~ Identity, so it can't use any fancy monad tricks, unless you pass it an argument. This sort of trick is used e.g. here and here.)
Given that m = return x, we know by the monad transformer laws (lift . return = return) that lift m = m.
Of course, this is only true for this particular type. If you have, say, m :: MonadState S m => m A, then m could easily be different from lift m -- for example, with a type like StateT A (State A) A, get and lift get will be different.
(And of course all of this is ignoring ⊥. Then again, if you don't, most monads don't obey the laws anyway.)

I believe this is a sloppy inductive proof that your m is equivalent to lift m.
I think we have to try to prove something about m (or rather, about all possible values of type (Monad m) => m A). If we consider Monad as consisting of bind and return only, and ignore bottom and fail then your m must at the top level be one of:
mA = return (x)
mB = (mX >>= f)
For mA the two forms of m are equivalent by the monad transformer law:
lift (return (x)) = return (x)
That's the base case. Then we're left with the second transformer law to reason about mB:
lift (mX >>= f) = lift mX >>= (lift . f)
and where we'd like to prove that that our mB is equal to that expansion:
mX >>= f = lift mX >>= (lift . f)
we assume that the left side of bind is equivalent (mX = lift mX) since that's our inductive hypothesis (right?).
So then we're left to prove f = lift . f by figuring out what f has to look like:
f :: a -> m b
f = \a -> (one of our forms mA or mB)
and lift . f looks like:
f = \a -> lift (one of our forms mA or mB)
Which leaves us back with our hypothesis:
m = lift m

Related

Is the monad transformer of a monad unique in Haskell?

There have been a couple of questions (e.g. this and this) asking whether every monad in Haskell (other than IO) has a corresponding monad transformer. Now I would like to ask a complementary question. Does every monad have exactly one transformer (or none as in the case of IO) or can it have more than one transformer?
A counterexample would be two monad transformers that would produce monads behaving identically when applied to the identity monad would but would produce differently behaving monads when applied to some other monad. If the answer is that a monad can have more than one transformer I would like to have a Haskell example which is as simple as possible. These don't have to be actually useful transformers (though that would be interesting).
Some of the answers in the linked question seemed to suggest that a monad could have more than one transformer. However, I don't know much category theory beyond the basic definition of a category so I wasn't sure whether they are an answer to this question.
Here's one idea for a counterexample to uniqueness. We know that in general, monads don't compose... but we also know that if there's an appropriate swap operation, you can compose them[1]! Let's make a class for monads that can swap with themselves.
-- | laws (from [1]):
-- swap . fmap (fmap f) = fmap (fmap f) . swap
-- swap . pure = fmap pure
-- swap . fmap pure = pure
-- fmap join . swap . fmap (join . fmap swap) = join . fmap swap . fmap join . swap
class Monad m => Swap m where
swap :: m (m a) -> m (m a)
instance Swap Identity where swap = id
instance Swap Maybe where
swap Nothing = Just Nothing
swap (Just Nothing) = Nothing
swap (Just (Just x)) = Just (Just x)
Then we can build a monad transformer that composes a monad with itself, like so:
newtype Twice m a = Twice (m (m a))
Hopefully it should be obvious what pure and (<$>) do. Rather than defining (>>=), I'll define join, as I think it's a bit more obvious what's going on; (>>=) can be derived from it.
instance Swap m => Monad (Twice m) where
join = id
. Twice -- rewrap newtype
. fmap join . join . fmap swap -- from [1]
. runTwice . fmap runTwice -- unwrap newtype
instance MonadTrans Twice where lift = Twice . pure
I haven't checked that lift obeys the MonadTrans laws for all Swap instances, but I did check them for Identity and Maybe.
Now, we have
IdentityT Identity ~= Identity ~= Twice Identity
IdentityT Maybe ~= Maybe !~= Twice Maybe
which shows that IdentityT is not a unique monad transformer for producing Identity.
[1] Composing monads by Mark P. Jones and Luc Duponcheel
The identity monad has at least two monad transformers: the identity monad transformer and the codensity monad transformer.
newtype IdentityT m a = IdentityT (m a)
newtype Codensity m a = Codensity (forall r. (a -> m r) -> m r)
Indeed, considering Codensity Identity, forall r. (a -> r) -> r is isomorphic to a.
These monad transformers are quite different. One example is that "bracket" can be defined as a monadic action in Codensity:
bracket :: Monad m => m () -> m () -> Codensity m ()
bracket before after = Codensity (\k -> before *> k () *> after)
whereas transposing that signature to IdentityT doesn't make much sense
bracket :: Monad m => m () -> m () -> IdentityT m () -- cannot implement the same functionality
Other examples can be found similarly from variants of the continuation/codensity monad, though I don't see a general scheme yet.
The state monad corresponds to the state monad transformer and to the composition of Codensity and ReaderT:
newtype StateT s m a = StateT (s -> m (s, a))
newtype CStateT s m a = CStateT (Codensity (ReaderT s m) a)
The list monad corresponds to at least three monad transformers, not including the wrong one:
newtype ListT m a = ListT (m (Maybe (a, ListT m a))) -- list-t
newtype LogicT m a = LogicT (forall r. (a -> m r -> m r) -> m r -> m r) -- logict
newtype MContT m a = MContT (forall r. Monoid r => (a -> m r) -> m r))
The first two can be found respectively in the packages list-t (also in an equivalent form in pipes),
and logict.
There is another example of a monad that has two inequivalent transformers: the "selection" monad.
type Sel r a = (a -> r) -> a
The monad is not well known but there are papers that mention it. Here is a package that refers to some papers:
https://hackage.haskell.org/package/transformers-0.6.0.4/docs/Control-Monad-Trans-Select.html
That package implements one transformer:
type SelT r m a = (a -> m r) -> m a
But there exists a second transformer:
type Sel2T r m a = (m a -> r ) -> m a
Proving laws for this transformer is more difficult but I have done it.
An advantage of the second transformer is that it is covariant in m, so the hoist function can be defined:
hoist :: (m a -> n a) -> Sel2T r m a -> Sel2T r n a
The second transformer is "fully featured", has all lifts and "hoist". The first transformer is not fully featured; for example, you cannot define blift :: Sel r a -> SelT r m a. In other words, you cannot embed monadic computations from Sel into SelT, just like you can't do that with the Continuation monad and the Codensity monad.
But with the Sel2T transformer, all lifts exist and you can embed Sel computations into Sel2T.
This example shows a monad with two transformers without using the Codensity construction in any way.

Monad transformer Inner structural order

I have been wondering why Monad Transformers has for example m(Maybe(m(Maybe a)) structural order and why not Maybe(m(Maybe( m a))). I have tried to implement the second one but I'm unable to complete it possibly BCS of my inadequate Haskell knowledge.
In all monad transformers, do we always have a structure like this?
if yes then why?
if not then when to choose one from another?
newtype MaybeOT m a = MaybeOT {runMaybeOT :: Maybe (m a) }
instance (Monad m) => Monad (MaybeOT m) where
return = pure
(MaybeOT mma) >>= f = MaybeOT $
case mma of
Nothing -> Nothing
(Just ma) -> inner ma where
inner ma = do
a <- ma
undefined
You've essentially discovered why monad transformers are inwards instead of outwards (nit: I'm pretty sure I'm not using correct terminology here, but you get what I mean - feel free to correct me here). It's much easier (easy == less constraints) to have the monad you know about be in the data position (inside), rather than the container position (outside). Intuitively, you can see why - after all, the monadic nature demands the container to be the same. You can do whatever you want with the data, but you must not change the type of the container during binding.
Of course, it's easier to realize all this by actually trying to implement the absurd. Which is what this is about. The final step you'll be stuck on while implementing >>=/bind for MaybeOT is this-
m a >>= ??? . runMaybeOT . f
Where, m is a Monad, m a :: m a, f :: a -> MaybeOT m a, and runMaybeOT :: MaybeOT m a -> Maybe (m a) (and also ??? :: ???, hehe)
Now, you must obtain a monad with the container type m to successfully bind on m a. But alas, you cannot get the m a out of Maybe (m a)! What happens when it's Nothing? Your primary tool in implementing monad transformers is knowledge about the specific monad you're implementing the transformer for. And your knowledge is telling you that this is absurd.
In contrast, the final step in implementing >>= for MaybeT goes well smoothly. For completeness, here's MaybeT-
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
Here, you'll be binding on the type m (Maybe a). During binding, you must return the type m b, for whatever b. You're given a function, f, of type a -> MaybeT m b, you can easily get m (Maybe b) from MaybeT m b.
Aha! Now you can see the solution. The function you're given returns the same outer monad as the one you're binding on. That is precisely what you need. In the case of MaybeOT, you were stuck with binding on the monad m, with a function that doesn't return a value with outer monad m!
And that is the crucial realization - the function you're given must be able to give you a value with the same outer monad. This is why MaybeT (and other transformers too) keeps the unknown monad outwards - because when you implement >>= for MaybeT, you know the binding function will be required to construct that outer monad.
It is helpful, at least intuitively, to note that the problem you get stuck on here - is the very same problem you'll face when implementing monadic composition. That is, >>= for nested monads. Monads don't compose! That's why you need monad transformers!
If you break this problem down, you'll notice that if you just had a function that could swap monads, to get Maybe (m a) from m (Maybe a) and vice versa - all would be well. Monads would compose, monad transformers could look like however you please, and in fact, monad transformers would essentially serve no purpose. This detail is noticed in the answer linked above. All you need is-
swap :: (Monad m, Monad n) => m (n a) -> n (m a)
This exists. They're called traversable monads, and indeed if you merely add the Traversable constraint to your Monad implementation for MaybeOT, you strike gold-
instance (Traversable m, Monad m) => Monad (MaybeOT m) where
return = pure
MaybeOT Nothing >>= _ = MaybeOT Nothing
MaybeOT (Just ma) >>= f = MaybeOT $ sequence $ ma >>= sequence . runMaybeOT . f
I assume it's law-conforming, though I'd have to check.
In another note, it is totally possible to make MaybeOT a law conforming applicative. After all, the problem you face while implementing Monad is simply non existent here. Applicatives do compose.
instance Applicative f => Applicative (MaybeT f) where
pure = MaybeT . pure . Just
MaybeT f <*> MaybeT a = MaybeT $ liftA2 (<*>) f a
(Or, perhaps more simply)
instance Applicative f => Applicative (MaybeT f) where
pure = MaybeT . pure . Just
MaybeT f <*> MaybeT a = MaybeT $ (<*>) <$> f <*> a
Which should be law conforming, as far as I can tell.

Why is this not a case of the restricted monad limitation?

In the following code snippet I initially believed to have a restricted monad error (I forgot to add the Monad m => in the instance Monad (Transform m a) definition). Having read quite a bit about restricted monads I wonder why this here happens to be ok:
{-# LANGUAGE GADTs #-}
data Next a where
Todo :: a -> Next a
Done :: Next a
instance Functor Next where
fmap f Done = Done
fmap f (Todo a) = Todo (f a)
data Transform m a b = Monad m => Transform ( m(Next a) -> m(Next b) )
instance Functor (Transform m a) where
fmap f (Transform ta) = Transform tb where
tb ma = ta ma >>= return . (fmap f)
instance Applicative (Transform m a) where
pure = return
mf <*> ma = do
f <- mf
a <- ma
return (f a)
instance Monad m => Monad (Transform m a) where
return b = Transform (t b) where
t b _ = return $ Todo b
(Transform t) >>= f = Transform (\ma -> do
a <- ma
case a of
Done -> return Done
--Todo a' -> ...
)
The example is rather contrived, I stripped away all irrelevant bits. (The actual problem at hand is related to this.) The crucial part is the Monad m restriction in Transform.
I don't quite see how this is different from the often-cited canonical Set-as-a-monad example, which does exhibit the restricted monad limitation.
Transform is not a restricted monad.
Look at Set. Set is monadic in its one argument, except said argument needs to be Ord. That is, Set is a monad on the subcategory of Hask where all the objects are in Ord.
But Transform is not a monad in the first place. Transform :: (* -> *) -> * -> * -> *, but Monad applies to things of kind * -> * (if you're going to go full category theorist, monads in general are endofunctors and should roughly have kind k -> k for some k, but Transform doesn't really fit that wider template either). The thing that is a monad is Transform m a when m is a monad. Transform m a is monad on all of Hask, as long as m is also a monad. You see the difference? Transform m a given Monad m operates on every type there is. But there is nothing I can put in the blank to make "Set given ___ operates on every type there is", because the restriction is going on the parameter that Set is monadic in, while Transform m a does not have a restriction on the type it is monadic in, but on one of the types that makes it up.
I don't quite see how this is different from the often-cited canonical Set-as-a-monad example, which does exhibit the restricted monad limitation.
It's different because the constraint isn't on the last type parameter, which is the one which varies in Monad. In the case of Set it is.

Use of a monad superclass in a monad instance declaration?

I'm implementing a very simple poor mans concurrency structure with the following data type:
data C m a = Atomic (m (C m a)) | Done a
I'm creating an instance of monad for this:
instance Monad m => Monad (C m) where
(>>=) (Atomic m) f = Atomic $ (liftM (>>= f) m)
(>>=) (Done v) f = f v
return = Done
Q1. Am I right in saying Atomic $ (liftM (>>= f) m) is creating a new Atomic monad which contains the result of f (* -> *) applied to the value inside of m?
Q2. Am I right in saying the superclass Monad m is used here to enable the use of liftM? If so, as this is an instance of the Monad class, why can't this access liftM directly?
Q1. It is creating Atomic value. Monad is a mapping at type level. Since f is the second argument of >>= of C m a we know its type
f :: Monad m => a -> C m b
hence
(>>= f) :: Monad m => C m a -> C m b
is f extended to unwrap its argument, and
liftM (>>= f) :: (Monad m1, Monad m) => m1 (C m a) -> m1 (C m b)
simply lifts the transformation into m1 which in your setting is unified with m. When you extract the value m from Atomic and pass it to liftM you use the monad m's bind (via liftM) to extract the inner C m a to be passed to f. The second part of liftM's definition re-wraps the result as a m (C m b) which you wrap in Atomic. So yes.
Q2. Yes. But it is a liftM of the underlying monad m. The liftM for C m a is defined in terms of the instance (its >>= and return). By using C m a's liftM (if you managed to define >>= in terms of liftM) you would get a cyclic definition. You need the constraint Monad m to create the plumbing for m (C m a) to travel through the >>= and f. In fact as pointed by Benjamin Hodgson, Monad m is an unnecessarily strong constaint, Functor m would suffice. The fact that C is in fact Free together with the relevant implementations give the most insight in the matter.

Monad Transformer: troubles defining bind due to different monads

I have a Monad of named TaskMonad, defined as follows:
data TaskMonad a = TaskMonad (Environment -> (TaskResult a, Environment))
where Environment is a record type and TaskResult is an ADT; but they are not important for the problem.
I have defed Functor, Applicative and Monad instances for TaskMonad, and I now want to be able to combine this monad with other Monads (e.g. IO), So I defined a new type as follows:
newtype Task m a = Task { runTask :: m (TaskMonad a) }
I have defined Functor and Applicative as follows:
instance Monad m => Functor (Task m) where
fmap f ta = Task $ do tma <- runTask ta
return (fmap f tma)
instance Monad m => Applicative (Task m) where
pure = Task . return . return
(<*>) prod tx = Task $ do tmprod <- runTask prod
tmtx <- runTask tx
return (tmprod <*> tmtx)
And I also made Task member of the MonadTrans class:
instance MonadTrans Task where
lift = Task . (liftM return)
So far so good (or atleast it compiles..), but now I want to define the instance for Monad, but I am running into problems here:
instance Monad m => Monad (Task m) where
return = pure
(>>=) ta tb = ...
I attempted multiple things, most attempts starting out like this:
(>>=) ta tb = Task $ do tma <- runTask ta
Now we have tma :: TaskMonad a inside the do block for the m monad. Now what I would like to do, is somehow calling the >>= instance for TaskMonad so I can get the result of tma, a value of type a so I can parameterize tb with it to obtain a value of Task b. But I am within the context of the m monad and I'm running into all kinds of problems.
How could I obtain tma's result to provide it to tb?
Okay, I don't know how much this helps, but if you actually start with a transformer from day 0 (in TaskMonad), the way you can do it is:
data TaskMonad m a = TaskMonad (Environment -> m (TaskResult a, Environment)) deriving Functor
instance Monad m => Monad (TaskMonad m) where
return = pure
(TaskMonad f) >>= b = TaskMonad $ \e -> do
(TaskResult r, e') <- f e
let (TaskMonad g) = b r
g e'
instance (Monad m, Functor m) => Applicative (TaskMonad m) where
pure a = TaskMonad $ \e -> return (TaskResult a, e)
(TaskMonad f) <*> (TaskMonad g) = TaskMonad $ \e -> do
(TaskResult f', e') <- f e
(TaskResult a, e'') <- g e'
return (TaskResult (f' a), e'')
Probably there's also a way to do that the way you originally intended, but I am pretty sure original Task would also need to be changed to take initial Environment.
I presume you're actually doing more than State in your monad, so that would need to be put in respective instances, but I think the framework for that should help.
And of course, shall you ever need to use a non-transformer version, just pass in Identity for m.
Disclaimer:
I know this implemenation of Applicative instance doesn't make sense, but I was building that on old GHC w/o ApplicativeDo and it was literally the easiest thing to put the silly constraint there.
As described in #BartekBanachewicz's answer, putting the monad m inside -> is the way to go.
I believe it's not possible to do it the way you want by having m (TaskMonad a), at least not generically. In general monads aren't closed under composition and this is an example of such a situation.
Let me give a simplified example (some theory will be required for it): Let's work with the reader monad instead of the state monad, let's drop TaskResult and let's have the environment as a type parameter. So TaskMonad will be just m (r -> a). Now let's assume it's a monad, then there is
join :: m (r -> (m (r -> a))) -> m (r -> a)
Specializing a to Void (see also Bottom type) and m to Either r we get
join :: Either r (r -> (Either r (r -> Void))) -> Either r (r -> Void)
But then we're able to construct
doubleNegationElimination :: Either r (r -> Void)
doubleNegationElimination = join (Right Left)
as Right Left :: Either r (r -> Either r (r -> Void)). Through Curry-Howard isomorphism this would mean that we'd be able to prove Double negation elimination
in intuitionistic logic, which is a contradiction.
Your situation is somewhat more complex, but a similar argument could be made there too. The only hole there is that we assumed that the "environment" part, r, was generic, so won't work if your join or >>= is somehow specific for Environment. So you might be able to do it in such a case, but my guess is you'll then encounter other problems preventing you to get a proper non-trivial Monad instance.

Resources