Function in Haskell to map over a MonadTrans?
haskell state monad
monad transformers haskell
I have recently decided to start using monad transformations instead of stacking my monads, since it seems it's the right thing to do. I wasn't really stacking many monads before anyway. I get (I think) the idea behind it and the
lift function, that, as I understand it, acts as a sort of
return for the transformation (puts something from the underlying monad into the transformed monad).
So far so good, but I don't see anything similar to an
fmap function for monad transformations. Let me give you an example. Say I have a custom monad,
m, and I use a
StateT transformation on it, therefore using the type
StateT s m a instead of
m (State s a).
Now, it so happens that in my monad
m, I have a function that transforms the monadic element (in fact it is one of the constructors of the monad, if you need details I can give) while keeping in some sense the underlying values:
myFunc :: m a -> m a.
So I'm building a recursive function
recFunc :: State s a -> [t] -> m (State s a) that looks similar to something like this:
recFunc :: State s a -> [t] -> m (State s a) recFunc x  = return x recFunc x (t:ts) = myFunc (recFunc x ts)
But if I try to replicate this using monad transformations, I run into problems because I can find no way to plug in
myFunc into the mix. It does not matter whether you write the input as
State s a or as
StateT s Identity a (which would be algebraically more precise?)
recFuncT :: StateT s Identity a -> [t] -> StateT s m a recFuncT x  = ??? recFuncT x (t:ts) = ????? where rec = recFuncT x ts
So what I'm looking for is something like the (invented, and don't know how I would implement, if possible) following functions:
transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a transmap = ??? transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a transreturn = ???
I have the feeling I should be able to define these using
lift, but I don't see how, to be honest.
If I had them, then I could do this:
recFuncT :: StateT s Identity a -> [t] -> StateT s m a recFuncT x  = transreturn (return x) recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)
Maybe what I really want is something more basic. I want the assumed isomorphism between
t m a and
m (t Identity a) to be explicit, so I'm looking for functions:
fromTrans :: t m a -> m (t Identity a) toTrans :: m (t Identity a) -> t m a
As far as I understand monad transformers, these functions should always exist and be fairly straightforward, right?
With these I could obviously implement
transmap :: (MonadTrans t, Monad m) => (forall b. m b -> m b) -> t m a -> t m a transmap f x = toTrans (f (fromTrans x)) transreturn :: (MonadTrans t, Monad m) => m (t Identity a) -> t m a transreturn = toTrans
I am sure there is something obvious that I am overlooking. Please point at it for me.
It appears that one concept you're seeking can be found in the
class MFunctor t where -- The argument is generally required to be a monad morphism, -- but some instances will work sensibly when it's not. hoist :: Monad m => (forall x. m x -> n x) -> t m a -> t n a
This is a little more general than your version because it allows the underlying monad to be replaced.
Control.Monad.Trans.Class, All of the monad transformers except ContT and SelectT are functors on the they also define a mapping from transformations between base monads to " Monadic parsing in Haskell", by Graham Hutton and Erik Meijer, Journal of Functional� (Currently these functions are defined as field labels, but in the next major release they will be separate functions.) All of the monad transformers except ContT and SelectT are functors on the category of monads: in addition to defining a mapping of monads, they also define a mapping from transformations between base monads to transformations
From the discussion in the comments, it sounds like what you really want is a monad transformer for your custom monad that is then applied to the base monad
State. In other words, to the extent that your custom monad is "nearly" a list:
newtype Listish a = Listish [a]
its transformer version would have type:
newtype ListishT m a = ListishT [m a]
and so your final monad transformer stack would be:
type M s = ListishT (State s)
which is isomorphic to your monad stack
[State s a] AKA Listish (State s a)
Be sure not to over-generalize the pattern for creating a transformer from an underlying monad, however. While transformers for some monads:
newtype List a = List [a] newtype Reader r a = Reader (r -> a)
are sensibly derived by replacing "
a" with "
newtype ListT m a = ListT [m a] newtype ReaderT r m a = ReaderT (r -> m a)
transformers for other types are derived differently. For example:
newtype State s a = State (s -> (a, s)) newtype Writer w a = Writer (a, w)
newtype StateT s a = StateT (s -> m (a, s)) -- **NOT** StateT (s -> (m a, s)) newtype WriterT s a = WriterT (m (a, w)) -- **NOT** WriterT (m a, w)
In particular, there is no monad transformer for
IO, because the simple substitution
newtype BadIOT m a = BadIOT (IO (m a))
is, as you point out, silly.
All About Monads, 3.4.1 The MonadTrans and MonadIO classes; 3.4.2 Transformer The mapM function maps a monadic computation over a list of values and� Map both the return value and the state of a computation using the given function. mGetRaw :: Monad m => MultiWriterT a m ( HList a) Source # A raw extractor of the contained HList (i.e. the complete state).
EDIT: All of the below makes no sense. I leave it strikedthrough. Good answer below.
For the record, my final solution was neither to use or implement a monad transformer, and instead simply implement the following function: (my custom monad is called
(..>>=) :: Monad m => EnumProc (m a) -> (a -> m b) -> EnumProc (m b) en ..>>= f = en <$> (>>= f) infixl 7 ..>>=
This allows me to deal with monadic computations inside my monad while keeping the outside monad structure. I was surprised myself when an
I then use
EnumProc (State s a) as type throughout.
Chapter 18. Monad transformers, Before we introduce monad transformers, let's look at a function written using techniques we are already familiar with. Monad.Trans (liftIO) import Control. Monad. We use a WriterT on top of IO because there is no IOT monad transformer. For teaching the language, it's good that map operates on lists, not on functors. The MonadTransControl type class is a stronger version of MonadTrans:. Instances of MonadTrans know how to lift actions in the base monad to the transformed monad. These lifted actions, however, are completely unaware of the monadic state added by the transformer.
After a while, I finally came up with exactly what I was looking for since the beginning. I can use
StateT exactly the way I wanted, and it has exactly the semantics I thought it had, but I did not explain it well (and put mistakes in what I wrote).
Going back to my original post, I need not have a
State as input, the
StateT monad already includes the input in the monadic element. So what I needed was a function
recFuncT :: [t] -> StateT s m a that behaved equivalently to the following non-transformer one:
recFunc :: a -> [t] -> m (State s a) recFunc x  = return (return x) recFunc x (t:ts) = myFunc (recFunc x ts)
It can be implemented directly, using the constructor
runStateT. Here it is:
recFuncT :: a -> [t] -> StateT m s a recFuncT x  = return x recFuncT x (t:ts) = StateT (\s -> myFunc (runStateT (recFuncT x ts) s))
Moreover, the function
transmap can also be implemented in general, at least for
transmap :: Monad m => (forall b. m b -> m b) -> StateT s m a -> StateT s m a transmap f st = StateT (\s -> f (runStateT st s)
And then we could write
recFuncT nicely in terms of it:
recFuncT :: a -> [t] -> StateT m s a recFuncT x  = return x recFuncT x (t:ts) = transmap myFunc (recFuncT x ts)
I realize this does not really match with the code that I included originally, but it does match with the overall principle I was trying to appeal to saying that the
StateT transformer is like adding state to my monad
m, and therefore anything that can be done at the
m (State s a) level can be done at the
StateT s m a level.
Stacking the ReaderT WriterT Monad Transformer Stack in Haskell, Stacking the ReaderT WriterT Monad Transformer Stack in Haskell. January 12 local - to map a function on the resource before using it: local :: (r -> r) Let's also have a look at the MonadTrans typeclass. It defines one� The mapAndUnzipM function maps its first argument over a list, returning the result as a pair of lists. This function is mainly used with complicated data structures or a state-transforming monad. This function is mainly used with complicated data structures or a state-transforming monad.
Issue deriving MonadTrans for chained custom monad transformers , After defining a set of monadic functions for this monad, I wanted to build a second Can't make a derived instance of 'MonadTrans CommandT' (even with cunning Window XRect)) deriving (Input (M.Map Window XRect), Output (M. Map little surprised to find no discussion on this given the overlap between the Haskell� Then we can perform three different lifting operations: liftM can be used both to transform a pure function into a function between inner monads and to a function between transformed monads, and finally lift transforms from the inner monad to the transformed monad. Because of the purity of Haskell, we can only lift "up".
Haskell Basics, Functions are the primary building block of all of Haskell logic. the Functor typeclass allows us to "map" a function generically over any type of Monad. Trans. Since many function names (but not the type name) clash with Prelude names, this module is usually imported qualified, e.g. import Data.Map (Map) import qualified Data.Map as Map The implementation of Map is based on size balanced binary trees (or trees of bounded balance) as described by:
CMSC-16100 — Lecture 23: Monad Transformer Library , class MonadTrans t where lift :: Monad m => m a -> t m a. i.e., IdentityT possesses a lift function that maps the untransformed monad m a into the Lazy relies on functional dependencies, an extension to Haskell implemented in GHC, but not� Note the kind signature of instances of the MonadTrans class: (*-> *)-> (*-> *). That is, every monad transformer type constructor takes a monad (kind *-> *) as an argument, and returns a monad (also *-> *) as a result. So all Monad Transformers are basically type-functions from monad types to different monad types which have additional traits.
State s a == StateT s Identity a, so
StateT s m aand
m (StateT s Identity a)are two different things. One is isomorphic to
m (s -> (a, s)), the other
s -> m (a, s).
- @chepner That is a fair point, but even if that is true, it still does not address my high level issue, namely: I am assuming the principle that if a monad has an associated transformer, then anything you can do by stacking monads you can do by using the transformer, call it the "Transformer Principle". So what I am trying to do, you can do by stacking monads, as showcased by my implementation
recFunc. Therefore, if the principle holds (and since the
Statemonad does have a transformer), there must be a way to do it with transformers. What is that way?
- Yes, but your conversion isn't just stacking monads.
recFuncTis different than
recFunc. If it were the same, you wouldn't have to change the body at all, because simply replacing
Statewith the equivalent
StateTis just alias expansion.
- @chepner I am pretty sure you must be missing the point. you can always replace
StateT, but not all instances of
StateTcan be directly replaced with an instance of
State. That is, whenever
mis not the Identity, then
StateT s m acannot be rewritten in terms of
State. However, conceptually and as I understand transformers,
StateT s m ais "inserting
m", and so should have at least all the functionality of
m (State s a). Are you saying this is not true, that there are things you can only do with
m (State s a)?
- I think the problem is that
StateT s m acan be viewed as "inserting
m", but the type
m (State s a)can't. It's not even clear what
m (State s a)is, at least for general monad
IO (State s a)? If it's supposed to be a monad, what does its bind operator look like? If it's not supposed to be a monad, what are its "capabilities"?
- It even has a predefined instance
MFunctor (StateT s), which is exactly what I wanted. This is exactly the answer I was initially looking for.
- Hm. But you could define that for any monad and it would not make sense. Why would it make more sense for this monad? You could implement:
newtype TransformerFromMonad tm m a = TransformerFromMonad (tm (m a))And then consider horrifying things like
TransformerFromMonad IO (State s) == IO (State s a)and which is nothing like a transformer for the
- I added a note about this.
- Maybe I am trying to generalize monad transformers too much, instead of taking them individually for what each of them are...
- Because of my low rep it doesn't let me set this one as accepted in the end. I realize I've changed my mind and changed the phrasing of the problem many times, but as I understand it this is normal when I am not an expert in what I'm talking about. I don't know what are exactly the policies of Stack Overflow when it comes to trying to leave this as not-a-mess. Let me know if I need to edit something, merge something, delete something or anything else and I'll try to do it. Thanks again to those who helped me get to the core of it.