2013-05-16 25 views
2

我知道数据构造函数和运行***函数,如何将函数提升到haskell中的已转换monad?

我可以将任何函数提升到特定的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 

但我怎么能概括这个liftF到

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

为什么不使用'liftM'? 't m'本身就是monad。 – thoferon

+0

@ thoferon,是的,但'liftM'也不是一般化的。因为在使用'liftM'之前我必须写'instance Monad(SomeMonadTrans m)',但是我仍然需要知道SomeMonadTrans。 – Znatz

回答

5

正如@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约束)。

但是,你为什么要这样做?检查出的源代码​​- 已经有一个单子实例:

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) 

而实际上,作为liftM是一样的函子的fmap

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

你可以找到类似的例子对所有变压器。

这是你在问什么?你能否提供一些更具体的例子来说明你想要做什么以及为什么,现有的Functor和Monad实例不能满足你的需求?

+0

我很抱歉我的英语。我的意思是,就'Monad'而言,只要'SomeType'是'Monad'的一个实例,我们就不需要重新定义'liftM'。对于通用的MonadTrans t,我必须在使用'liftM'之前定义't m''Monad'。有没有办法跳过这一步?或者说,对于每个通用的'MonadTrans'实例是否有通用的'liftF'? – Znatz

+1

@Znatz但是在标准库中,作为'MonadTrans'实例的每个数据类型也是'Monad'的一个实例,所以'liftM'将与所有变换器一起工作。 –

+0

@Znatz你能举一个例子,这不起作用吗? –