[Haskell-beginners] Mixing IO and other monads

Brian Victor homeusenet4 at brianhv.org
Sun Aug 29 18:56:06 EDT 2010

I've managed to create the sort of nested case code that all the monad
tutorials warn you against.  I haven't found a way to work myself out of
it, though.  If I've understood monad transformers conceptually, this
seems like the sort of thing they'd be good for, but I don't know how to
actually make what I need.

Here's the code I have.  getDefaultInputDeviceID and
getDefaultOutputDeviceID are from PortMidi, and return IO (Maybe Int).
openInput and openOutput return IO (Either PMStream PMError).  At this
point, I'd be happy to get the second half of the function refactored
into monads.

main :: IO ()
main = do
    ideviceId <- getDefaultInputDeviceID
    case ideviceId of
        Nothing -> putStrLn "No default input device"
        Just inputDeviceId -> do
            odeviceId <- getDefaultOutputDeviceID
            case odeviceId of
                Nothing -> putStrLn "No default output device"
                Just outputDeviceId -> do
                    openInputResult <- openInput inputDeviceId
                    case openInputResult of
                        Right err -> putStrLn $ show err
                        Left inputStream -> do
                            openOutputResult <- openOutput outputDeviceId 0
                            case openOutputResult of
                                Right err -> putStrLn $ show err
                                Left outputStream -> runTranslationLoop inputStream outputStream

It seems like I ought to be able to change the second half of the
function to something like this:

openStreamsAndLoop :: (Num a) => a -> a -> IO (Maybe err)
openStreamsAndLoop inputDeviceId outputDeviceId = do
    inputStream <- openInput inputDeviceId
    outputStream <- openOutput outputDeviceId 0
    runTranslationLoop inputStream outputStream
    return Nothing

But how do I create an IO (Maybe err) monad?


More information about the Beginners mailing list