title: How to simplify the error handling in (IO (Either a b))
body: <p>I'm using the following scenario as an example to learn how to handle errors in a simple way. The scenario is basically read a file path from an environment variable, then read and print the file with the file path. </p>
  
  <p>The following code works, but I don't like the <code>printFile</code> because it has nested <code>case of</code>, a bit hard to read. I wonder if there is a clean way to get rid of it and keep the <code>printFile</code> function flat without using <code>lookupEnv</code>?</p>
  
  <p>How would you simplify this error handling flow?</p>
  
  <pre><code>module Main where
  
  import Control.Exception (IOException, handle, throw)
  import System.Environment (getEnv)
  import System.IO.Error (isDoesNotExistError)
  
  data MissingError
    = MissingEnv String
    | MissingFile String
    deriving (Show)
  
  main :: IO ()
  main = do
    eitherFile &lt;- printFile
    either print print eitherFile
  
  getEnv' :: String -&gt; MissingError -&gt; IO (Either MissingError String)
  getEnv' env err = handle (missingEnv err) $ Right &lt;$&gt; (getEnv env)
  
  readFile' :: FilePath -&gt; MissingError -&gt; IO (Either MissingError String)
  readFile' path err = handle (missingFile err) $ Right &lt;$&gt; (readFile path)
  
  missingEnv :: MissingError -&gt; IOException -&gt; IO (Either MissingError String)
  missingEnv err = const $ return $ Left err
  
  missingFile :: MissingError -&gt; IOException -&gt; IO (Either MissingError String)
  missingFile err e
    | isDoesNotExistError e = return $ Left err
    | otherwise = throw e
  
  printFile :: IO (Either MissingError String)
  printFile = do
    eitherFilePath &lt;- getEnv' "FOLDER" (MissingEnv "FOLDER")
    case eitherFilePath of
      Left err -&gt; return $ Left err
      Right path -&gt; readFile' path (MissingFile path)
  </code></pre>