[Haskell-beginners] Mixing IO and other monads

Henk-Jan van Tuyl hjgtuyl at chello.nl
Mon Aug 30 07:50:31 EDT 2010


On Mon, 30 Aug 2010 00:56:06 +0200, Brian Victor <homeusenet4 at brianhv.org>  
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
>
>

This can be made more readable if main is split up:

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

This can be made more compact with the aid of the following two functions:

> ifLeft x f =
>   x' <- x
>   case x' of
>     Right err -> putStrLn $ show err
>     Left  y   -> f y

> ifJust x f msg =
>   x' <- x
>   case x' of
>     Nothing -> putStrLn msg
>     Just y  -> f y

The main program than becomes:

> main :: IO ()
> main =  do
>     initialize
>     ifJust getDefaultInputDeviceID
>       main2      "No default input device"
>
>     where
>       main2 inputDeviceId =        ifJust getDefaultOutputDeviceID 
>           (main3 inputDeviceId)          "No default output device"
>
>       main3 inputDeviceId outputDeviceId =
>         ifLeft (openInput inputDeviceId)
>           (main4 inputDeviceId outputDeviceId)
>
>       main4 inputDeviceId outputDeviceId inputStream =
>         ifLeft (openOutput outputDeviceId 0) 
>           (runTranslationLoop inputStream)


Of course, another thing to prevent long lines, is to use two spaces for  
indentation.

Met vriendelijke groet,
Henk-Jan van Tuyl


-- 
http://Van.Tuyl.eu/
http://members.chello.nl/hjgtuyl/tourdemonad.html
--


More information about the Beginners mailing list