Personal tools

Bracket pattern

From HaskellWiki

(Difference between revisions)
Jump to: navigation, search
(link to continuation)
 
(One intermediate revision by one user not shown)
Line 36: Line 36:
 
(\rs -> withArray0 nullPtr rs act)
 
(\rs -> withArray0 nullPtr rs act)
 
</haskell>
 
</haskell>
  +
  +
== See also ==
  +
  +
* [[Continuation]]
  +
  +
[[Category:Idioms]]

Latest revision as of 11:08, 5 June 2012

When acquiring, using, and releasing various resources, it can be quite convenient to write a function to manage the acquisition and releasing, taking a function of the acquired value that specifies an action to be performed in between.

The function
bracket
from
Control.Exception
can be used to build such functions in the IO monad. It is commonly partially applied to its first two parameters, giving a function which manages the resource in question, allocating it for the context of a specific action.
bracket :: IO a        -- computation to run first ("acquire resource")
        -> (a -> IO b) -- computation to run last ("release resource")
        -> (a -> IO c) -- computation to run in-between
        -> IO c
In general, throughout the libraries many functions having names beginning with
with
are defined to manage various resources in this fashion. One passes in a function of the allocated resource that says what to do, and the with-function handles both the allocation and deallocation. For example, in
System.IO
, there is a function:
withFile :: FilePath -> IOMode -> (Handle -> IO r) -> IO r
that manages opening and closing a filehandle, or in
Foreign.Marshal.Array
, there is a function
withArray :: Storable a => [a] -> (Ptr a -> IO b) -> IO b

which manages the memory associated with a foreign array.

A common thing one might want to do is to collect up a list of such resource-managing with-functions and build from them a single with-function that manages the whole list of associated resources.

For this one can use what is effectively
sequence
in the
Cont
monad, "unwrapped" appropriately:
nest :: [(r -> a) -> a] -> ([r] -> a) -> a
nest xs = runCont (sequence (map Cont xs))
As an example of the use of
nest
, here is a with-function that allocates each of a list of
Strings
as a
CString
(which as the name suggests, is a C-style pointer to an allocated block of memory holding the characters of the string), and then allocates a null-terminated array holding these
CString
s, runs the given action, then deallocates all the resources.
withCStringArray0 :: [String] -> (Ptr CString -> IO a) -> IO a
withCStringArray0 strings act = nest (map withCString strings)
                                     (\rs -> withArray0 nullPtr rs act)

[edit] See also