Following a haskell tutorial, the author provides the following implementation of the withFile method:
withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
withFile' path mode f = do
handle <- openFile path mode
result <- f handle
hClose handle
return result
But why do we need to wrap the result
in a return
? Doesn't the supplied function f
already return an IO
as can be seen by it's type Handle -> IO a
?
You're right: f
already returns an IO
, so if the function were written like this:
withFile' path mode f = do
handle <- openFile path mode
f handle
there would be no need for a return. The problem is hClose handle
comes in between, so we have to store the result first:
result <- f handle
and doing <-
gets rid of the IO
. So return
puts it back.
This is one of the tricky little things that confused me when I first tried Haskell. You're misunderstanding the meaning of the <-
construct in do-notation. result <- f handle
doesn't mean "assign the value of f handle
to result
"; it means "bind result
to a value 'extracted' from the monadic value of f handle
" (where the 'extraction' happens in some way that's defined by the particular Monad instance that you're using, in this case the IO monad).
I.e., for some Monad typeclass m, the <-
statement takes an expression of type m a
in the right hand side and a variable of type a
on the left hand side, and binds the variable to a value. Thus in your particular example, with result <- f handle
, we have the types f result :: IO a
, result :: a
and return result :: IO a
.
PS do-notation has also a special form of let
(without the in
keyword in this case!) that works as a pure counterpart to <-
. So you could rewrite your example as:
withFile' :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
withFile' path mode f = do
handle <- openFile path mode
let result = f handle
hClose handle
result
In this case, because the let
is a straightforward assignment, the type of result
is IO a
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With