Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refactoring “staircasing” with case of `Maybe` values in `IO` code

The following function f attempts to read an Int twice by using an IO (Maybe Int) function twice, but “short-circuits” execution after successfully reading one Int:

readInt :: IO (Maybe Int)

f :: IO (Maybe Int)
f = do
  n1 <- readInt
  case n1 of
      Just n' -> return (Just n')
      Nothing -> do
        n2 <- readInt
        case n2 of
              Just n' -> return (Just n')
              Nothing -> return Nothing

Is there a good way to refactor this code? This would get very hairy if I extended it to three attempts…

(My thought process: Seeing this “staircasing” tells me that maybe I should be using the Monad instance of Maybe, but since this is already in the IO monad, I would then have to use MaybeT(?). However, I only need one of the readInt to succeed, so the Maybe monad's behaviour of erroring out on the first Nothing would be wrong here...)

like image 950
beta Avatar asked Jan 24 '15 11:01

beta


1 Answers

You can use MaybeT and the MonadPlus instance to use msum:

f :: MaybeT IO Int
f = msum [readInt, readInt, readInt]
like image 83
Lee Avatar answered Sep 29 '22 03:09

Lee