Q:

Either monad to IO monad - simple and idiomatic way?

This code compiles:
read :: IO Config
read = do
  c1 <- BS.readFile "my_config.yaml"
  case Y.decodeEither' c1 of
    Right x -> pure x
    Left e -> error "error 123"

where this doesn't:
read :: IO Config
read = do
  liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
    Right x -> pure x
    Left e -> error "error 123"

===>
  Expected type: IO Config
    Actual type: Either a1 Config

How can I transform Either monad to IO one? I'd like a simple and idiomatic way, with no additional libraries.

A:

The line BS.readFile "my_config.yaml" >>= Y.decodeEither' does not make much sense, since decodeEither' :: FromJSON a => ByteString -> Either ParseException a itself does not return an IO a, and BS.readFile is not an Either ParseException b, so it has neither an IO monadic context, or an Either a monadic context.
What you can do is perform a functor mapping on the result, so Y.decodeEither' <$> BS.readFile "my_config.yaml", but then this has as type FromJSON a => IO (Either ParseException a), so you can not use pattern matching with Left and Right on that.
You can however implement this as:
read :: IO Config
read = do
    result <- Y.decodeEither <$> BS.readFile "my_config.yaml"
    case result of
        Right x -> pure x
        Left e -> error e
or you can, like @JosephSible says perform the mapping in the case part:
read :: IO Config
read = do
    result <- BS.readFile "my_config.yaml"
    case Y.decodeEither result of
        Right x -> pure x
        Left e -> error e

