双重fmap应用程序

时间:2014-10-16 12:24:39

标签: haskell applicative

让我们假设我们有

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

data Foo = Foo String String

我希望从Maybe Fooa获得b

目前,我正在这样做

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
              ...

2 个答案:

答案 0 :(得分:3)

可能是最简单的解决方案:

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

liftM2也有效。我更喜欢尽可能最弱的可接受的解决方案(并且随着即将到来的Applicative-Monad对GHC 7.10进行超级分类,这将完全没有争议)。

或者,如果经常显示IO (Maybe a),您可以使用monad变换器,这样您就可以使用liftA2 / liftM2提升任意数量的monad:

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

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

答案 1 :(得分: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