If you want to use a file in Haskell, you have two options. You can open and close the file yourself:
openFile :: FilePath -> IOMode -> IO Handle hClose :: Handle -> IO ()
… or you can use a function that takes care of the open-close lifecycle:
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
Which is the better interface? It’s a trade-off:
withFile guarantees that every open file is closed, while
hClose allow you to open and close files in any order.
Let’s create types to represent these two kinds of interface:
type OpenClose h = IO (h,IO ()) -- opens a resource, returns a handle and a "closer" type With h = forall r. (h -> IO r) -> IO r openCloseFile :: FilePath -> IOMode -> OpenClose Handle openCloseFile path mode = do h <- openFile path mode return (h, hClose h) withFile :: FilePath -> IOMode -> With Handle -- already defined
Is it possible to convert between the two? Here’s how to obtain a
With interface from an
openCloseToWith :: OpenClose h -> With h openCloseToWith oc f = do (h, closer) <- oc finally (f h) closer
It’s also possible to obtain an
OpenClose interface from a
With interface. Can you see how?
withToOpenClose :: With h -> OpenClose h withToOpenClose = ...?
— Ashley Yakeley