2014-10-16 7 views
3

Давайте предположим, что мы имеемДвукратное БПМЖ применение

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

data Foo = Foo String String 

И я хочу, чтобы получить Maybe Foo от a и b.

В настоящее время я делаю это

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

Но я чувствую, что должен быть более простой способ,

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

ли трюк, но я не хочу, чтобы создать что уродливая лямбда там. Есть ли такой оператор, как <$>, но с двухкратным приложением? Или есть ли способ объединить IO (Just a), чтобы иметь одну монаду?

Edit:

Я думаю, тип подписи:

(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 (\ аЬ -> Foo <$><*> б)' – josejuan

+4

Вы можете использовать 'а, Ь: : MaybeT IO String'. Тогда это просто 'Foo <$> a <*> b'. –

ответ

3

Вероятно, самое простое решение:

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

liftM2 также работает. Я предпочитаю хотя бы самое слабое приемлемое решение (и с наступающим аппликативно-монадским суперклассированием с 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 s не сочиняет , Applicative s делаю. После упаковки всех вещей в подходящем newtype вы получите это (см Control.Compose или Data.Functor.Compose):

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

 Смежные вопросы

  • Нет связанных вопросов^_^