Anatomy of a monad transformer - haskell

I'm trying to learn monad transformers, based on the standard Haskell libraries (mtl? transformers? not sure which one came with my download of the Haskell platform - 7.4.1).
What I believe I've noticed is a common structure for each monad transformer definition:
base type ('Base')
Monad instance
transformer type ('BaseT')
Monad instance
MonadTrans instance
MonadIO instance
transformer class ('MonadBase')
some operations
instances for other 'BaseT's
So for example, for the Writer monad, there'd be:
a Writer datatype/newtype/type, with a Monad instance
a WriterT datatype/newtype/type, with Monad, MonadTrans, and MonadIO instances
a MonadWriter class, and instances of this class for StateT, ReaderT, IdentityT, ...
Is this how monad transformers are organized? Am I missing anything/do I have any incorrect details?
The motivation for this question is figuring out:
what the relationships and differences are between the "BaseT"s and the corresponding "MonadBase"s and "Base"s
whether all three are required
how MonadTrans is related and what its purpose is

mtl package doesn't implement monad transformers. At least WriterT is just reexported from transformers.
transformers package implements WriterT, which is a monad transformer itself. Writer is just an alias:
type Writer w = WriterT w Identity
Some libraries can implement Writer separately, but anyway it is just a special case of WriterT. (Identity is a trivial monad, it doesn't have any additional behavior.)
MonadTrans allows you to wrap underlying monad into the transformed one. You can live without it, but you will need to perform manual wrapping (see MonadTrans instance definition for WriterT for example how to do it). The only use case where you really need MonadTrans -- when you don't know actual type of transformer.
MonadWriter is a type class declared in mtl. It's methods (writer, pass, tell and listen) are the same as function for WriterT. It allows to wrap (automatically!) WriterT computation through stack of transformers, even if you don't know exact types (and even number!) of transformers in the stack.
So, WriterT is the only type which is "required".
For other monad transformers it is the same: BaseT is a transformer, Base is a monad without underlying monad and MonadBase is a type class -- class of all monads, that have BaseT somewhere in transformers stack.
ADDED:
You can find great explanation in RWH book
Here is a basic example:
import Control.Monad.Trans
import Control.Monad.Trans.Writer
import Control.Monad.Trans.Reader hiding (ask)
-- `ask` from transformers
-- ask :: Monad m => ReaderT r m r
import qualified Control.Monad.Trans.Reader as TransReader (ask)
-- `ask` from mtl
-- ask :: MonadReader r m => m r
import qualified Control.Monad.Reader as MtlReader (ask)
-- Our monad transformer stack:
-- It supports reading Int and writing String
type M m a = WriterT String (ReaderT Int m) a
-- Run our monad
runM :: Monad m => Int -> M m a -> m (a, String)
runM i action = runReaderT (runWriterT action) i
test :: Monad m => M m Int
test = do
tell "hello"
-- v <- TransReader.ask -- (I) will not compile
v1 <- lift TransReader.ask -- (II) ok
v2 <- MtlReader.ask -- (III) ok
return (v1 + v2)
main :: IO ()
main = runM 123 test >>= print
Note that (I) will be rejected by compiler (try it to see the error message!). But (II) compiles, thanks to MonadTrans ("explicit lifting"). Thanks to MonadReader, (III) works out of the box ("implicit lifting"). Please read RWH book for explanation how it works.
(In the example we import ask from two different modules, that is why we need qualified import. Usually you will use only one of them at a time.)
Also I didn't mean to specifically ask about Writer.
Not sure I understand... Reader, State and others use the same schema. Replace Writer with State and you will have an explanation for State.

Related

Why no MonadWriter instance for ParsecT?

I was writing some Haskell earlier today. Came up with something along the lines of
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
newtype Foo a = Foo { ParsecT String () (Writer DefinitelyAMonoid) a }
deriving (Functor, Applicative, Monad, MonadWriter DefinitelyAMonoid)
This did not compile. "No instance for (MonadWriter DefinitelyAMonoid (ParsecT String () (Writer DefinitelyAMonoid))) arising from the 'deriving' clause of a data type declaration", GHC told me. So I decided to see if some other MTL classes would work, and they did. Reader and MonadReader, and Writer and MonadWriter. So I turned was directed by a Discord user to Hackage, where the problem was clear:
MonadState s m => MonadState s (ParsecT s' u m)
MonadReader r m => MonadReader r (ParsecT s u m)
MonadError e m => MonadError e (ParsecT s u m)
No MonadWriter instance can make it through the ParsecT transformer! Seemed for all the world to me like a mere oversight, and I just barely realized before opening an issue on Github that this might be deliberate. So I took a look at Megaparsec:
(Stream s, MonadState st m) => MonadState st (ParsecT e s m)
(Stream s, MonadReader r m) => MonadReader r (ParsecT e s m)
(Stream s, MonadError e' m) => MonadError e' (ParsecT e s m)
Again, no MonadWriter.
Why do neither Parsec nor Megaparsec provide a MonadWriter instance for ParsecT? Is there something special about parser monads like these that keep them from playing nice with writers? Is there something similar to this going on?
Parsec is a backtracking monad. While the MonadWriter instance you propose is not impossible, it's a strange thing to put a Writer underneath a backtracking monad. This is because the inner layers of a monad stack provide the "foundational" effects upon which the outer layers build -- that is, whatever ParsecT u (Writer w) does, it must do so only in terms of tell. So if it tells a value in a branch that is later backtracked out of, there is no possibility to "untell" that value, and so the Writer's result will be more like a trace of the parsing algorithm rather than a trace of the dataflow abstraction that Parsec is presenting. It's not useless, but it's pretty odd, and you would have much more natural semantics if WriterT were on the outside and Parsec on the inside.
The same argument applies to State. Parsec exposes both its own user state functionality (the u parameter) and a MonadState instance that inherits the underlying monad's state functionality. The latter comes with the same caveats as MonadWriter -- the statefulness follows the trace of the algorithm, not the dataflow. I don't know why this instance was included while the Writer instance was not; they are both tricky in the same way.
-- I'm presuming the user might want a separate, non-backtracking
-- state aside from the Parsec user state.
instance (MonadState s m) => MonadState s (ParsecT s' u m) where
get = lift get
put = lift . put
Parsec's user state, on the other hand, follows the dataflow, not computation, and it has the same effect as putting StateT on the outside. It always seemed odd that Parsec provides its own state facility rather than just asking us to use a transformer -- but, thinking about it now, I suspect it is just to avoid having to put lift all over the place if you do happen to use state.
In conclusion, they could provide the MonadWriter instance you ask for, but I think there is a decent reason not to -- to discourage making the mistake that I think you are probably making.

Haskell - MonadState

So I have recently been looking at state monads because I want to build a parser combinator library in haskell.
I came across a typeclass known as MonadState, I was wondering what is the point of this typeclass and where would you use it?
MonadState abstracts out the get and put functions so that they work not just for one type, but for any type that can act as a state monad. It's primarily to make monad transformers work.
Without going into too much detail, let's just assume you know that StateT exists: it takes one monad and returns a new monad that can act as state. (I'll ignore the difference between lazy and strict state monads here). A monad that handles state can then be defined by applying StateT to the Identity monad:
newtype State s = StateT s Identity
As long as the input type is a monad, we can provide a MonadState instance for the monad returned by StateT:
-- Add state to any monad
instance Monad m => MonadState s (StateT s m) where
...
This says that applying StateT to any monad (not just Identity) produces a monad that can be treated as a state monad.
Further, you can say that anything that wraps a state monad is also a state monad, as long as it implements MonadState:
-- Add Maybe to a state monad, it's still a state monad
instance MonadState s m => MonadState s (MaybeT m) where
...
-- Add Writer to a state monad, it's still a state monad
instance (Monoid w, MonadState s m) => MonadState s (WriterT w m) where
...
MonadState abstracts the state monad (as if this stuff wasn't abstract enough, right?). Instead of requiring a concrete type State with a Monad instance, it lets us use any Monad we like, provided we can provide appropriate get and put functions. In particular, we can use StateT which lets us combine effects.
simple example combining State and IO:
tick :: (MonadIO m, MonadState Int m) => m ()
tick = do
x <- get
liftIO $ putStrLn ("incrementing " ++ (show x))
put (x+1)
> runStateT (tick >> tick >> tick >> tick) 5
incrementing 5
incrementing 6
incrementing 7
incrementing 8
((),9)

Why are monad transformers different to stacking monads?

In many cases, it isn't clear to me what is to be gained by combining two monads with a transformer rather than using two separate monads. Obviously, using two separate monads is a hassle and can involve do notation inside do notation, but are there cases where it just isn't expressive enough?
One case seems to be StateT on List: combining monads doesn't get you the right type, and if you do obtain the right type via a stack of monads like Bar (where Bar a = (Reader r (List (Writer w (Identity a))), it doesn't do the right thing.
But I'd like a more general and technical understanding of exactly what monad transformers are bringing to the table, when they are and aren't necessary, and why.
To make this question a little more focused:
What is an actual example of a monad with no corresponding transformer (this would help illustrate what transformers can do that just stacking monads can't).
Are StateT and ContT the only transformers that give a type not equivalent to the composition of them with m, for an underlying monad m (regardless of which order they're composed.)
(I'm not interested in particular implementation details as regards different choices of libraries, but rather the general (and probably Haskell independent) question of what monad transformers/morphisms are adding as an alternative to combining effects by stacking a bunch of monadic type constructors.)
(To give a little context, I'm a linguist who's doing a project to enrich Montague grammar - simply typed lambda calculus for composing word meanings into sentences - with a monad transformer stack. It would be really helpful to understand whether transformers are actually doing anything useful for me.)
Thanks,
Reuben
To answer you question about the difference between Writer w (Maybe a) vs MaybeT (Writer w) a, let's start by taking a look at the definitions:
newtype WriterT w m a = WriterT { runWriterT :: m (a, w) }
type Writer w = WriterT w Identity
newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }
Using ~~ to mean "structurally similar to" we have:
Writer w (Maybe a) == WriterT w Identity (Maybe a)
~~ Identity (Maybe a, w)
~~ (Maybe a, w)
MaybeT (Writer w) a ~~ (Writer w) (Maybe a)
== Writer w (Maybe a)
... same derivation as above ...
~~ (Maybe a, w)
So in a sense you are correct -- structurally both Writer w (Maybe a) and MaybeT (Writer w) a
are the same - both are essentially just a pair of a Maybe value and a w.
The difference is how we treat them as monadic values.
The return and >>= class functions do very different things depending
on which monad they are part of.
Let's consider the pair (Just 3, []::[String]). Using the association
we have derived above here's how that pair would be expressed in both monads:
three_W :: Writer String (Maybe Int)
three_W = return (Just 3)
three_M :: MaybeT (Writer String) Int
three_M = return 3
And here is how we would construct a the pair (Nothing, []):
nutin_W :: Writer String (Maybe Int)
nutin_W = return Nothing
nutin_M :: MaybeT (Writer String) Int
nutin_M = MaybeT (return Nothing) -- could also use mzero
Now consider this function on pairs:
add1 :: (Maybe Int, String) -> (Maybe Int, String)
add1 (Nothing, w) = (Nothing w)
add1 (Just x, w) = (Just (x+1), w)
and let's see how we would implement it in the two different monads:
add1_W :: Writer String (Maybe Int) -> Writer String (Maybe Int)
add1_W e = do x <- e
case x of
Nothing -> return Nothing
Just y -> return (Just (y+1))
add1_M :: MaybeT (Writer String) Int -> MaybeT (Writer String) Int
add1_M e = do x <- e; return (e+1)
-- also could use: fmap (+1) e
In general you'll see that the code in the MaybeT monad is more concise.
Moreover, semantically the two monads are very different...
MaybeT (Writer w) a is a Writer-action which can fail, and the failure is
automatically handled for you. Writer w (Maybe a) is just a Writer
action which returns a Maybe. Nothing special happens if that Maybe value
turns out to be Nothing. This is exemplified in the add1_W function where
we had to perform a case analysis on x.
Another reason to prefer the MaybeT approach is that we can write code
which is generic over any monad stack. For instance, the function:
square x = do tell ("computing the square of " ++ show x)
return (x*x)
can be used unchanged in any monad stack which has a Writer String, e.g.:
WriterT String IO
ReaderT (WriterT String Maybe)
MaybeT (Writer String)
StateT (WriterT String (ReaderT Char IO))
...
But the return value of square does not type check against Writer String (Maybe Int) because square does not return a Maybe.
When you code in Writer String (Maybe Int), you code explicitly reveals
the structure of monad making it less generic. This definition of add1_W:
add1_W e = do x <- e
return $ do
y <- x
return $ y + 1
only works in a two-layer monad stack whereas a function like square
works in a much more general setting.
What is an actual example of a monad with no corresponding transformer (this would help illustrate what transformers can do that just stacking monads can't).
IO and ST are the canonical examples here.
Are StateT and ContT the only transformers that give a type not equivalent to the composition of them with m, for an underlying monad m (regardless of which order they're composed.)
No, ListT m a is not (isomorphic to) [m a]:
newtype ListT m a =
ListT { unListT :: m (Maybe (a, ListT m a)) }
To make this question a little more focused:
What is an actual example of a monad with no corresponding transformer (this would help illustrate what transformers can do that just stacking monads can't).
There are no known examples of a monad that lacks a transformer, as long as the monad is defined explicitly as a pure lambda-calculus term, with no side effects and no external libraries being used. The Haskell monads such as IO and ST are essentially interfaces to an external library defined by low-level code. Those monads cannot be defined by pure lambda-calculus, and their monad transformers probably do not exist.
Even though there are no known explicit examples of monads without transformers, there is also no known general method or algorithm for obtaining a monad transformer for a given monad. If I define some complicated monad, for example like this code in Haskell:
type D a = Either a ((a -> Bool) -> Maybe a)
then it is far from obvious how to define a transformer for the monad D.
This D a may look a contrived and artificial example (and it's also not obvious why it is a monad) but there might be legitimate cases for using that monad, which is a "free pointed monad on the Search monad on Maybe".
To clarify: A "search monad on n" is the type S n q a = (a -> n q) -> n a where n is another monad and q is a fixed type.
A "free pointed monad on M" is the type P a = Either a (M a) where M is another monad.
In any case, I just want to illustrate the point. I don't think it would be easy for anyone to come up with the monad transformer for D and then to prove that it satisfies the laws of monad transformers. There is no known algorithm that takes the code of D and outputs the code of its transformer.
Are StateT and ContT the only transformers that give a type not equivalent to the composition of them with m, for an underlying monad m (regardless of which order they're composed.)
Monad transformers are necessary because stacking two monads is not always a monad. Most "simple" monads, like Reader, Writer, Maybe, etc., stack with other monads in a particular order. But the result of stacking, say, Writer + Reader + Maybe, is a more complicated monad that no longer allows stacking with new monads.
There are several examples of monads that do not stack at all: State, Cont, List, Free monads, the Codensity monad, and a few other, less well known monads, like the "free pointed" monad shown above.
For each of those "non-stacking" monads, one needs to guess the correct monad transformer somehow.
I have studied this question for a while and I have assembled a list of techniques for creating monad transformers, together with full proofs of all laws. There doesn't seem to be any system to creating a monad transformer for a specific monad. I even found a couple of monads that have two inequivalent transformers.
Generally, monad transformers can be classified in 6 different families:
Functor composition in one or another order: EitherT, WriterT, ReaderT and a generalization of Reader to a special class of monads, called "rigid" monads. An example of a "rigid" monad is Q a = (H a) -> a where H is an arbitrary (but fixed) contravariant functor.
The "adjunction recipe": StateT, ContT, CodensityT, SearchT, which gives transformers that are not functorial.
The "recursive recipe": ListT, FreeT
Cartesian product of monads: If M and N are monads then their Cartesian product, type P a = (M a, N a) is also a monad whose transformer is the Cartesian product of transformers.
The free pointed monad: P a = Either a (M a) where M is another monad. For that monad, the transformer's type is m (Either a (MT m a)) where MT is the monad M's transformer.
Monad stacks, that is, monads obtained by applying one or more monad transformers to some other monad. A monad stack's transformer is build via a special recipe that uses all the transformers of the individual monads in the stack.
There may be monads that do not fit into any of these cases, but I have seen no examples so far.
Details and proofs of these constructions of monad transformers are in my draft book here https://github.com/winitzki/sofp

Monad Transformer stacks with MaybeT and RandT

I'm trying to learn how Monad Transformers work by re-factoring something I wrote when I first learned Haskell. It has quite a few components that could be replaced with a (rather large) stack of Monad Transformers.
I started by writing a type alias for my stack:
type SolverT a = MaybeT
(WriterT Leaderboard
(ReaderT Problem
(StateT SolutionState
(Rand StdGen)))) a
A quick rundown:
Rand threads through a StdGen used in various random operations
StateT carries the state of the solution as it gets progressively evaluated
ReaderT has a fixed state Problem space being solved
WriterT has a leaderboard constantly updated by the solution with the best version(s) so far
MaybeT is needed because both the problem and solution state use lookup from Data.Map, and any error in how they are configured would lead to a Nothing
In the original version a Nothing "never" happened because I only used a Map for efficient lookups for known key/value pairs (I suppose I could refactor to use an array). In the original I got around the Maybe problem by making a liberal use of fromJust.
From what I understand having MaybeT at the top means that in the event of a Nothing in any SolverT a I don't lose any of the information in my other transformers, as they are unwrapped from outside-in.
Side question
[EDIT: This was a problem because I didn't use a sandbox, so I had old/conflicting versions of libraries causing an issue]
When I first wrote the stack I had RandT at the top. I decided to avoid using lift everywhere or writing my own instance declarations for all the other transformers for RandT. So I moved it to the bottom.
I did try writing an instance declaration for MonadReader and this was about as much as I could get to compile:
instance (MonadReader r m,RandomGen g) => MonadReader r (RandT g m) where
ask = undefined
local = undefined
reader = undefined
I just couldn't get any combination of lift, liftRand and liftRandT to work in the definition. It's not particularly important but I am curious about what a valid definition might be?
Problem 1
[EDIT: This was a problem because I didn't use a sandbox, so I had old/conflicting versions of libraries causing an issue]
Even though MonadRandom has instances of everything (except MaybeT) I still had to write my own instance declarations for each Transformer:
instance (MonadRandom m) => MonadRandom (MaybeT m) where
getRandom = lift getRandom
getRandomR = lift . getRandomR
getRandoms = lift getRandoms
getRandomRs = lift . getRandomRs
I did this for WriterT, ReaderT and StateT by copying the instances from the MonadRandom source code. Note: for StateT and WriterT they do use qualified imports but not for Reader. If I didn't write my own declarations I got errors like this:
No instance for (MonadRandom (ReaderT Problem (StateT SolutionState (Rand StdGen))))
arising from a use of `getRandomR'
I'm not quite sure why this is happening.
Problem 2
With the above in hand, I re-wrote one of my functions:
randomCity :: SolverT City
randomCity = do
cits <- asks getCities
x <- getRandomR (0,M.size cits -1)
--rc <- M.lookup x cits
return undefined --rc
The above compiles and I think is how transformers are suppose to be used. In-spite of the tedium of having to write repetitive transformer instances, this is pretty handy. You'll notice that in the above I've commented out two parts. If I remove the comments I get:
Couldn't match type `Maybe'
with `MaybeT
(WriterT
Leaderboard
(ReaderT Problem (StateT SolutionState (Rand StdGen))))'
Expected type: MaybeT
(WriterT
Leaderboard (ReaderT Problem (StateT SolutionState (Rand StdGen))))
City
Actual type: Maybe City
At first I thought the problem was about the types of Monads that they are. All of the other Monads in the stack have a constructor for (\s -> (a,s)) while Maybe has Just a | Nothing. But that shouldn't make a difference, the type for ask should return Reader r a, while lookup k m should give a type Maybe a.
I thought I would check my assumption, so I went into GHCI and checked these types:
> :t ask
ask :: MonadReader r m => m r
> :t (Just 5)
(Just 5) :: Num a => Maybe a
> :t MaybeT 5
MaybeT 5 :: Num (m (Maybe a)) => MaybeT m a
I can see that all of my other transformers define a type class that can be lifted through a transformer. MaybeT doesn't seem to have a MonadMaybe typeclass.
I know that with lift I can lift something from my transformer stack into MaybeT, so that I can end up with MaybeT m a. But if I end up with Maybe a I assumed that I could bind it in a do block with <-.
Problem 3
I actually have one more thing to add to my stack and I'm not sure where it should go. The Solver operates on a fixed number of cycles. I need to keep track of the current cycle vs the max cycle. I could add the cycle count to the solution state, but I'm wondering if there is an additional transformer I could add.
Further to that, how many transformers is too many? I know this is incredibly subjective but surely there is a performance cost on these transformers? I imagine some amount of fusion can optimise this at compile time so maybe the performance cost is minimal?
Problem 1
Can't reproduce. There are already these instances for RandT.
Problem 2
lookup returns Maybe, but you have a stack based on MaybeT. The reason why there is no MonadMaybe is that the corresponding type class is MonadPlus (or more general Alternative) - pure/return correspond to Just and empty/mzero correspond to Nothing. I'd suggest to create a helper
lookupA :: (Alternative f, Ord k) => k -> M.Map k v -> f v
lookupA k = maybe empty pure . M.lookup k
and then you can call lookupA wherever you need in your monad stack
As mentioned in the comments, I'd strongly suggest to use RWST, as it's exactly what fits your case, and it's much easier to work with than the stack of StateT/ReaderT/WriterT.
Also think about the difference between
type Solver a = RWST Problem Leaderboard SolutionState (MaybeT (Rand StdGen)) a
and
type Solver a = MaybeT (RWST Problem Leaderboard SolutionState (Rand StdGen)) a
The difference is what happens in the case of a failure. The former stack doesn't return anything, while the latter allows you to retrieve the state and the Leaderboard computed so far.
Problem 3
The easiest way is to add it into the state part. I'd just include it into SolutionState.
Sample code
import Control.Applicative
import Control.Monad.Random
import Control.Monad.Random.Class
import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad.RWS
import qualified Data.Map as M
import Data.Monoid
import System.Random
-- Dummy data types to satisfy the compiler
data Problem = Problem
data Leaderboard = Leaderboard
data SolutionState = SolutionState
data City = City
instance Monoid Leaderboard where
mempty = Leaderboard
mappend _ _ = Leaderboard
-- dummy function
getCities :: Problem -> M.Map Int City
getCities _ = M.singleton 0 City
-- the actual sample code
type Solver a = RWST Problem Leaderboard SolutionState (MaybeT (Rand StdGen)) a
lookupA :: (Alternative f, Ord k) => k -> M.Map k v -> f v
lookupA k = maybe empty pure . M.lookup k
randomCity :: Solver City
randomCity = do
cits <- asks getCities
x <- getRandomR (0, M.size cits - 1)
lookupA x cits

Why aren't monad transformers constrained to yield monads?

In the MonadTrans class:
class MonadTrans t where
-- | Lift a computation from the argument monad to the constructed monad.
lift :: Monad m => m a -> t m a
why isn't t m constrained to be a Monad? i.e., why not:
{-# LANGUAGE MultiParamTypeClasses #-}
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
If the answer is "because that's just the way it is", that's fine -- it's just confusing for a n008.
You suggested the following:
class Monad (t m) => MonadTrans t m where
lift :: Monad m => m a -> t m a
...but does that really mean what you want? It seems you want to express something like "a type t may be an instance of MonadTrans if, for all m :: * -> * where m is an instance of Monad, t m is also an instance of Monad".
What the class definition above actually says is more like "types t and m may constitute an instance of MonadTrans if, for those specific types, t m is an instance of Monad". Consider carefully the difference, and the implied potential for instances that may not be what you'd want.
In the general case, every parameter of a type class is an independent "argument", a fact which has been a bountiful source of both headaches and GHC extensions as people have attempted to use MPTCs.
Which isn't to say that such a definition couldn't be used anyway--as you point out, the current definition is not ideal either. The age-old problem "Why Data.Set Is Not a Functor" is related, and such issues helped motivate the recent ConstraintKinds tomfoolery.
The ultimate answer to "why not" here is almost certainly the one given by Daniel Fischer in the comments--because MonadTrans is pretty core functionality, it would be undesirable to make it depend on some terrifying cascade of increasingly arcane GHC extensions.

Resources