The split-channel package is new library that is a small variation on Control.Concurrent.Chan. The most obvious change is that it splits the channel into sending and receiving ports. This has at least two advantages: first, that this enables the type system to more finely constrain program behavior, and second, a SendPort can have zero ReceivePorts associated with it, and messages written to such a channel can be garbage collected.

This library started life last fall as part of my experiments in adding support for PostgreSQL’s asynchronous notifications to Chris Done’s native pgsql-simple library. The initial motivation was that if a notification arrived and nobody was listening, I wanted to be able to garbage collect it. However, the type advantages are what keep me coming back.

Beyond the primary change, this library has a number of other small improvements over Control.Concurrent.Chan : the deprecated thread-unsafe functions aren’t there, and several operators have been added or improved, most notably listen , sendMany , fold , and split .

listen attaches a new ReceivePort to an existing SendPort . By contrast, Chan only provides the ability to duplicate an existing ReceivePort . Edit: I was mistaken: listen is essentially equivalent to dupChan , whereas duplicate is new. sendMany sends a list of messages atomically. It’s a better name than writeList2Chan , which is not atomic and is only a convenience function written in terms of send . However, writeList2Chan does work on infinite streams, whereas sendMany does not. fold is a generalization of getChanContents , potentially avoiding some data structures. split cuts an existing channel into two channels. It gives you back a new ReceivePort associated with the existing SendPort , and a new SendPort associated with the existing ReceivePorts . This is a more general operator than one I’ve used in a few places to transparently swap out backend services. Chan does not provide the split operator, though one could be added. However I am skeptical that this is a good idea: it’s just a little too effect-ful for comfort. I think that putting a SendPort in an MVar tends to be a better idea than using split , even though it does introduce another layer of indirection.

Finally, a few acknowledgements are in order: primarily, Control.Concurrent.Chan and its authors and contributors, and secondarily, Joey Adams for GHC Bug #5870, the fix of which has been incorporated into split-channel.