2013-05-16 48 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你能舉一個例子,這不起作用嗎? –