[Haskell-beginners] Mixing IO and other monads

Brandon S Allbery KF8NH allbery at ece.cmu.edu
Mon Aug 30 11:53:12 EDT 2010


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 8/29/10 18:56 , Brian Victor wrote:
> main :: IO ()
> main = do
>     initialize
>     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?

You don't really need one; use the existing plumbing.

> ioE :: e -> IO (Maybe a) -> IO a
> ioE e a = a >>= \r -> case r of
>                         Just r' -> r'
>                         Nothing -> fail e
>
> io :: IO (Either e a) -> IO a
> io a = a >>= \r -> case r of
>                       Right v -> v
>                       Left e  -> fail $ show e
>
> main = do
>   initialize
>   iDeviceId <- ioE "No default input device" getDefaultInputDeviceId
>   oDeviceId <- ioE "No default output device" getDefaultOutputDeviceId
>   inputStream <- io $ openInput inputDeviceId
>   outputStream <- io $ openOutput outputDeviceId 0
>   runTranslationLoop inputStream outputStream

If you really want a monad transformer, ErrorT is probably the one to look
at (Control.Monad.Error).  But it won't be pretty unless you rewrite the
functions getDefault(...) and open(...) to use it as well.

- -- 
brandon s. allbery     [linux,solaris,freebsd,perl]      allbery at kf8nh.com
system administrator  [openafs,heimdal,too many hats]  allbery at ece.cmu.edu
electrical and computer engineering, carnegie mellon university      KF8NH
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.10 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkx70+cACgkQIn7hlCsL25V+7QCgkBPSUIzfpnRX69utD7o8d4oz
8FkAn3Sn47biInZg7dp56rThwamVmzu9
=tPWe
-----END PGP SIGNATURE-----


More information about the Beginners mailing list