Function in Haskell to map over a MonadTrans?

haskell monad
haskell state monad
haskell lift
monad transformers haskell
haskell monadplus
liftio haskell
haskell writert
haskell readert

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 and transreturn:

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.

Thanks.

It appears that one concept you're seeking can be found in the mmorph package:

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 "m a":

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)

give:

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 EnumProc):

(..>>=) :: 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 fmap sufficed.

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 State/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 StateT and 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 StateT:

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.

Comments
  • State s a == StateT s Identity a, so StateT s m a and 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 State monad 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. recFuncT is different than recFunc. If it were the same, you wouldn't have to change the body at all, because simply replacing State with the equivalent StateT is just alias expansion.
  • @chepner I am pretty sure you must be missing the point. you can always replace State with StateT, but not all instances of StateT can be directly replaced with an instance of State. That is, whenever m is not the Identity, then StateT s m a cannot be rewritten in terms of State. However, conceptually and as I understand transformers, StateT s m a is "inserting State capabilities inside 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 a can be viewed as "inserting State capabilities inside 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 m. What's 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 IO monad.
  • 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.