Trying to understand the pattern used to deal with possible failures inside IO
. If its just one case
s like below, its probably acceptable, but if the nesting goes on for a bunch of nested IO (Either String Int)
s is there a common pattern to handle such types. For instance, if b
in functionDoSomething
is again a (Either a b)
and fetching value on success and doing something with it again will be another such case
. Is there a higher order function that I can use? I'm not comfortable with monad transformers yet, not sure if they can be used to deal with this specific monad stack. If they can be used here, is there a way to do it without using them.
import Control.Monad
functionCreate :: Int -> IO (Either String Int)
functionDoSomething :: Int -> IO b
functionUse :: IO ()
functionUse = do
created <- functionCreate 10
case created of
(Right v) -> void $ functionDoSomething v
_ -> return ()
I understand that you're new to Haskell, and that monad transformers aren't the first concept you'd want to grapple with. In a situation like this, it is, however, the pattern to use.
Monads in general enable you to 'weave in and out of functors', so to speak. Had you only had Either
, you could have used the Either
values with do
notation to pull the Right
values out of the values, while short-circuiting the Left
cases.
In this case, however, you have a 'stack' of monads: Either
inside of IO
. Thus, when you attempt to use do
notation, you're in the IO
context, and that means that, as the OP illustrates, the values that you 'pull out of' the functions, using the <-
arrow, are still Either
values.
Monad transformers enable you to treat stacks of monads (like, in this case Either
values inside of IO
) as Monad
instances, so that you can, e.g., use do
notation on the stack.
While you'd expect the Either
monad transformer to be called EitherT
, it is, for various reasons, called ExceptT
. You could simplify the OP code slightly like this:
import Control.Monad (void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except
functionUse :: IO (Either String ())
functionUse = runExceptT $ do
created <- ExceptT $ functionCreate 10
liftIO $ void $ functionDoSomething created
Here, created
is an Int
value, which can then be passed to functionDoSomething
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With