Defer in Haskell

In Haskell, we don’t have a direct equivalent of the defer keyword. However, we can achieve similar functionality using the bracket function from the Control.Exception module. This function ensures that a resource is properly released after use, even if an exception occurs.

Here’s how we can implement the file creation, writing, and closing example in Haskell:

import System.IO
import Control.Exception (bracket)
import System.Exit (exitFailure)

main :: IO ()
main = bracket (createFile "/tmp/defer.txt") closeFile writeFile

createFile :: FilePath -> IO Handle
createFile path = do
    putStrLn "creating"
    handle <- openFile path WriteMode
    return handle

writeFile :: Handle -> IO ()
writeFile handle = do
    putStrLn "writing"
    hPutStrLn handle "data"

closeFile :: Handle -> IO ()
closeFile handle = do
    putStrLn "closing"
    hClose handle

In this Haskell version:

  1. We use the bracket function to ensure that the file is closed after we’re done with it. bracket takes three arguments:

    • A function to acquire the resource (createFile)
    • A function to release the resource (closeFile)
    • A function to use the resource (writeFile)
  2. The createFile function opens a file for writing and returns a Handle.

  3. The writeFile function writes some data to the file.

  4. The closeFile function closes the file handle.

  5. The main function uses bracket to tie these operations together, ensuring that the file is closed even if an exception occurs during writing.

To run the program:

$ runhaskell defer.hs
creating
writing
closing

This Haskell implementation achieves the same goal as the original example, ensuring that resources are properly managed and cleaned up, even in the presence of exceptions.

Note that Haskell’s type system and its emphasis on pure functions make it less common to need explicit resource management like this. In many cases, you might use higher-level abstractions that handle resource management automatically. However, when you do need to manage resources explicitly, the bracket function (and related functions in the Control.Exception module) provide a powerful and flexible way to do so.