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.
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 <- BS.readFile "my_config.yaml"
case 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 of
Right x -> pure x
Left e -> error e
No need to use do
or liftIO
here.
read :: IO Config
read = Y.decodeEither' <$> BS.readFile "my_config.yaml" >>= \c -> case c of
Right x -> pure x
Left e -> error "error 123"
should do it.
However it could be nicer to use the ExceptT
transformer then all you need to do would be
read :: ExceptT ParseException IO Config
read = ExceptT $ Y.decodeEither <$> BS.readFile "my_config.yaml"
Now you can do like;
configure :: ExceptT ParseException IO ()
configure = read >>= pure . processConfig
or as reminded by @Joseph Sible-Reinstate Monica like
configure :: ExceptT ParseException IO ()
configure = processConfig <$> read
and if decodeEither
returns a Left
value it gets logged and processConfig:: Config -> ()
gets skipped.
read :: IO Config
read = do
liftIO $ case (BS.readFile "my_config.yaml") >>= Y.decodeEither' of
Right x -> pure x
Left e -> error "error 123"
In the above incorrect attempt it almost looks like you want -XLambdaCase:
fmap Y.decodeEither' (BS.readFile "my_config.yaml) >>= \case
Right x -> pure x
Left e -> error "error 123"
But I find either
more readable:
either (error "error 123") pure . Y.decodeEither' =<< BS.readFile "my_config.yaml"
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.