Sure!
convert :: Either a (IO b) -> IO (Either a b)
convert = either (return . Left) (fmap Right)
Now, if you wanted to convert IO (Either a b) to Either a (IO b), you'd be in trouble, but you don't, so you're ok.
Let's see how convert works:
either :: (a -> c) -> (b -> c) -> Either a b -> c, so it takes care of pattern matching for us, figuring out whether we have an a or an IO b in your case.
- if we have an
a, we just need to convert it to a IO (Either a b). The constructor Left :: a -> Either a b does the first part, and IO is a monad, so we can use return to do Either a b -> IO (Either a b).
if we have an IO b, we need to convert it to a IO (Either a b). We could do this with do notation:
given iob = do
b <- iob
return . Right $ b
using return . Right as b -> IO (Either a b). But this is exactly the situation that mapM :: Monad m => (a -> b) -> m a -> m b is for in Monads: given iob = mapM Right iob. Most people don't use mapM, though, as it's just the specialization of fmap to Monads, so we'll use fmap : given iob = fmap Right iob, or, pointfree : given = fmap Right.