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:
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
)
- A function to acquire the resource (
The
createFile
function opens a file for writing and returns aHandle
.The
writeFile
function writes some data to the file.The
closeFile
function closes the file handle.The
main
function usesbracket
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.