Pregunta

I know with the data constructor and the run*** function,

I can lift any function to a specific MonadTrans instance.

Like this,

import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad

liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f x = MaybeT $ do
       inner <- runMaybeT x
       return $ liftM f inner

But how can I generalize this liftF to

liftF :: (MonadTrans t, Monad m) => (a -> b) -> t m a -> t m b
¿Fue útil?

Solución

As @thoferon mentioned, you can just use liftM:

import Control.Monad.Trans
import Control.Monad.Trans.Maybe
import Control.Monad (liftM)

liftF :: (Monad m) => (a -> b) -> MaybeT m a -> MaybeT m b
liftF f m = liftM f m

liftF' :: (MonadTrans t, Monad m, Monad (t m)) => (a -> b) -> t m a -> t m b
liftF' f m = liftM f m

(I had to add an additional Monad constraint to liftF').

But why would you do this? Check out the source code for MaybeT -- there's already a Monad instance:

instance (Monad m) => Monad (MaybeT m) where
    fail _ = MaybeT (return Nothing)
    return = lift . return
    x >>= f = MaybeT $ do
        v <- runMaybeT x
        case v of
            Nothing -> return Nothing
            Just y  -> runMaybeT (f y)

And actually, as liftM is the same as Functor's fmap:

instance (Functor m) => Functor (MaybeT m) where
    fmap f = mapMaybeT (fmap (fmap f))

You can find similar instances for all the transformers.

Is this what you are asking? Can you provide some more concrete examples that show what you're trying to do and why, and in what way the existing Functor and Monad instances fail to meet your needs?

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top