undo_all
undo_all

Reputation: 139

Converting Either a (IO b) to IO (Either a b)

Once again, through some bad, bad programming, I have managed to get myself into an awful situation with types.

Is there any way to convert Either a (IO b) to IO (Either a b)? I know, it's not very good programming to get myself into this situation, so I'd also be open to suggestions on how to avoid situations like this.

Upvotes: 2

Views: 641

Answers (1)

rampion
rampion

Reputation: 89053

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.

Upvotes: 6

Related Questions