Как поднять функцию преобразованной монаде в haskell?

Я знаю конструктор данных и функцию run ***,

Я могу поднять любую функцию до конкретного экземпляра MonadTrans.

Нравится,

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

Но как я могу обобщить этот подъем F на

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

person Znatz    schedule 16.05.2013    source источник
comment
Почему бы не использовать liftM? t m - это сама монада.   -  person tomferon    schedule 16.05.2013
comment
@ thoferon, да, но liftM тоже не является обобщенным. Поскольку я должен написать instance Monad (SomeMonadTrans m) where ... перед использованием liftM, мне все еще нужно знать SomeMonadTrans.   -  person Znatz    schedule 16.05.2013


Ответы (1)


Как упоминал @thoferon, вы можете просто использовать 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

(Мне пришлось добавить к liftF' дополнительное ограничение Monad).

Но зачем вам это делать? Ознакомьтесь с исходным кодом MaybeT - экземпляр Monad уже есть:

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)

Фактически, as liftM то же самое, что fmap в Functor:

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

Вы можете найти похожие экземпляры для всех трансформаторов.

Вы об этом спрашиваете? Можете ли вы привести еще несколько конкретных примеров, которые показывают, что вы пытаетесь сделать и почему, и каким образом существующие экземпляры Functor и Monad не соответствуют вашим потребностям?

person Matt Fenwick    schedule 17.05.2013
comment
Прошу прощения за мой английский. Я имею в виду, что в случае Monad, пока SomeType является экземпляром Monad, нам не нужно переопределять liftM. В случае общего MonadTrans t я должен определить t m a Monad перед использованием liftM. Есть ли способ пропустить этот шаг? Или сказать, есть ли универсальный liftF для всех общих MonadTrans экземпляров? - person Znatz; 18.05.2013
comment
@Znatz, но в стандартных библиотеках каждый тип данных, являющийся экземпляром MonadTrans, также является экземпляром Monad, так что liftM будет работать из коробки со всеми преобразователями. - person Matt Fenwick; 18.05.2013
comment
Спасибо. Я вижу сейчас. Мне нужно либо сделать шаг по определению моего универсального экземпляра MonadTrans t => t m как экземпляра Monad, либо использовать конструктор данных моего экземпляра. - person Znatz; 19.05.2013