2014-10-16 53 views
3

讓我們假設我們有2倍FMAP應用

a :: IO (Maybe String) 
b :: IO (Maybe String) 

data Foo = Foo String String 

我想從ab獲得Maybe Foo

目前,我正在做這個

do 
    a' <- a 
    b' <- b 
    Foo <$> a' <*> b' 

但是,我覺得應該有一個更簡單的方法,

(\x y -> Foo <$> x <*> y) <$> (Just <$> getLine) <*> (return Nothing) 

的伎倆,但我不希望創建醜陋的lambda在那裏。是否有像<$>這樣的運營商,但有雙重申請?或者有什麼辦法可以將IO (Just a)合併爲一個monad?

編輯:

我覺得類型的簽名是:

(Monad m, Monad n) => (a -> b -> c) -> (m (n a)) -> (m (n b)) -> (m (n c)) 

EDIT2:

對不起,我沒有說清楚,我的數據結構有兩個以上的領域,這是實際上是一個具有15個字段的配置結構。

cfg <- Conf.load [ Conf.Required cfile ] 

foo1 <- (Conf.lookup cfg "foo1" :: Maybe String) 
foo2 <- Conf.lookup cfg "foo2" 
foo3 <- Conf.lookup cfg "foo3" 
foo4, foo5, foo6... 

return $ Conf <$> foo1 
       <*> foo2 
       <*> foo3 
       <*> foo4 
       ... 
+1

你可以用'liftM2(\ AB - >富<$>一個<*> B)' – josejuan 2014-10-16 12:39:50

+4

你可以用'A,B: :MaybeT IO String'。然後它只是'Foo <$> a <*> b'。 – 2014-10-16 13:01:40

回答

3

也許最簡單的辦法:

(liftA2 . liftA2) Foo :: IO (Maybe String) -> IO (Maybe String) -> IO (Maybe Foo) 

liftM2也適用。我更喜歡儘管最弱的可接受的解決方案(以及即將到來的Applicative-Monad超級GHC 7.10,這將完全沒有爭議)。

另外,如果IO (Maybe a)頻繁出現時,你可以使用一個單子轉換,並且這樣你可以任意數量的單子解除了與liftA2/liftM2

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

liftA2 Foo :: MaybeT IO String -> MaybeT IO String -> MaybeT IO Foo 
1

好,而Monad■不要撰寫,Applicative這樣做。包裝所有的東西在合適的newtype後,你得到這個(見Control.ComposeData.Functor.Compose):

import Control.Compose 
a :: (IO :. Maybe) String 
b :: (IO :. Maybe) String 
result :: (IO :. Maybe) Foo 
result = Foo <$> a <*> b