Two-time fmap application

Let's pretend that

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

data Foo = Foo String String

      

And I want to get Maybe Foo

out of a

and b

.

I am currently doing this

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

      

But I feel like there must be an easier way,

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

      

There is a trick, but I don't want to create this ugly lambda. Is there a type operator <$>

but with a double appended? Or is there a way to combine IO (Just a)

with one monad?

Edit:

I think a signature like:

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

      

Edit2:

Sorry for the obscurity, my data structure has more than two fields, it is actually a configuration structure with ~ 15 fields.

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

      

+3


source to share


2 answers


Perhaps the simplest solution:

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

      

liftM2

also works. I prefer at least the weakest acceptable solution (and with the upcoming applicative-monadic superclassing since GHC 7.10 it will be completely indisputable).



Alternatively, if IO (Maybe a)

it appears frequently, you can use a monad transformer, and this way you can raise any number of monads with liftA2

/ liftM2

:

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

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

      

+3


source


Well, Monad

not to compose, Applicative

do. After wrapping all things in a suitable one, newtype

you get this (see Control.Compose

or Data.Functor.Compose

):



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

      

+1


source







All Articles