Sam Stites

Double brackets

writeStuff :: [Char] -> IO ()
writeStuff filename =
  bracket openFiles closeFiles doStuff
  where
    openFiles :: IO (Handle, Handle)
    openFiles = do
      f0 <- openFile (filename ++ "_first")  WriteMode
      f1 <- openFile (filename ++ "_second") WriteMode
      return (f0, f1)

    closeFiles :: (Handle, Handle) -> IO ()
    closeFiles (f0, f1) = do
      hClose f0
      hClose f1

    doStuff :: (Handle, Handle) -> IO ()
    doStuff = undefined -- etc

Bad! don’t duplicate your brackets! Notice in openFiles:

openFiles :: IO (Handle, Handle)
openFiles = do
  f0 <- openFile (filename ++ "_first")  WriteMode -- what happens if this breaks?
  f1 <- openFile (filename ++ "_second") WriteMode
  return (f0, f1)

See that question? Well, what happens is that you be able to properly close both of those files. The correct way of going about this is to nest your brackets:

writeStuff :: [Char] -> IO ()
writeStuff filename =
  bracket openOne hClose (\hdl1 ->
    bracket openTwo hClose (\hdl2 ->
      dooStuff hdl1 hdl2 ) )
  where
    openOne :: IO Handle
    openOne = openFile (filename ++ "_first")  WriteMode

    openTwo :: IO Handle
    openTwo = openFile (filename ++ "_second") WriteMode

    doStuff :: Handle -> Handle -> IO ()
    doStuff = undefined -- etc