The with pattern or bracket pattern is a functional programming idiom, a particular instance of Continuation-Passing Style, whereby one component that controls some resource that is consumed by another component of the system, is created via a function that takes as argument a function consuming the resource, instead of returning it. This pattern allows safe reclaiming of resources when the "wrapped" action terminates, whether normally or unexpectedly.
TODO "Tying the knot"
We use this pattern to provide interfaces to all active components, which exchange messages with other components of the system. A prototypical signature of such a component could be:
type Component m = inmsg -> m ()
type Callback m = outmsg -> m ()
withXXX :: Callback m -> (Component m -> m a) -> m a
withXXX can also allocate resources in order to provide
or use the
Callback, e.g. fork threads which invoke
Callback, but also make
sure they are cleaned up.
Components can be layered on top of another to provide additional behavior given the same interface. This also similar to "decorating" in the object-orientation world.
Component is agnostic about the messages it consumes/produces, it can be defined as a
Contravariant functor and the
Callback part as a (covariant)
Functor. This makes it possible to use
contramap operations to transform messages.