Proposal: split Chan and TChan into read and write ends

Oren Ben-Kiki haskell-oren at
Sat Oct 27 09:00:21 CEST 2012

I can't speak to the implications of changing the API, but the concept of
separating the reader and writer ends of a channel makes absolute sense. So
at the very least, this would be useful as a separate package.

In a side node - I used to code in an old concurrent language where even
variables were split into reader and writer ends (at the lowest level, not
as a library). That is, each use of "x" was either "the reader of x" or
"the writer of x". The compiler automatically infrerred which one was used,
but manual annotation was possible. The compiler also enforced that only a
single occurence of "the writer of x" existed at any given time in the

This allowed doing things that are difficult to do in Haskell right now,
without dropping into IO for IVars, such as passing around a deep structure
with writers at the leaves to a function that would fill them with values,
establishing a trivial two-way communication between multiple threads, and
difference lists rather than lists being the most common collection
(implemented as a simple pair of a Reader [ T ] and a Writer [ T ]).

Extensive use of difference lists turned out to be very useful - in naive
code list concatenation was O(1) in many more cases than in naive Haskell
code, and there are all sort of concurrency control algorithms that can be
trivially implemented by them (e.g., detecting/enforcing when a lazy
evaluation of multiple threads is done, passing exceptions in a side
channel to the real result, etc.).

It is a different approach than the one took by lazy functional languages,
and it has its up-sides; I miss its clarity of expressing the code intent
when I am dealing with parallel lazy Haskell code. It would be "very nice"
if there was a pure version of IVars that basically allowed direct
lower-level access to the lazy evaluation mechanism.

Of course, the language I used had other issues (this was the early 90s,
and a lot of work has been done since then on type systems and type
inference, efficient implementation, etc.). It was a research language that
dies with the 5th generation project :-(

At any rate, +1 for separate reader and writer endpoints for channels, at
least for those who need it.

Oren Ben-Kiki

On Sat, Oct 27, 2012 at 5:23 AM, Brandon Simmons <
brandon.m.simmons at> wrote:

> Hi everybody,
> Just discovered all the great discussion here, and although my
> google-fu turned up no prior discussions on this subject, I apologize
> if it has already been discussed.
> I propose that Chan and TChan should be implemented as a pair of read
> and write ends, initialized as follows:
>     newSplitChan :: IO (InChan a, OutChan a)
> I've implemented this already here:
> . You can ignore the
> type classes I've defined; they're there for my own reasons and not
> part of the proposal.
> Here is my best defense:
> 1) My own (and I assume others') use of Chans involves some bits of
> code which do only reads, and others which do only writes; a split
> implementation lets us use the type-checker to allocate read or write
> "permissions" when we pass around either end, and generally makes
> things easier to reason about. Others have independently reached this
> conclusion as well.
> 2) The API is simpler (and in the case of TChans *much* simpler) with
> a split approach; some examples: in TChan the types of the 'duplicate'
> functions actually suggest (IMHO) the details of how they treat
> existing messages, and require a less roundabout explanation
>     dupTChan :: InTChan a -> STM (OutTChan a)
>     cloneTChan :: OutTChan a -> STM (OutTChan a)
> another example, 'newBroadcastTChan' is actually just:
>     -- | Create a new write end of a TChan. Use dupTChan to get an
> OutChan that values can be read from.
>     newInTChan :: STM (InTChan a)
> and doesn't require any explanation beyond that.
> 3) It's trivial to modify the *Chan libs in this way with a few edits
> (really, they're already implemented this way, but with some added
> contortions to return both a read and write end for each operation),
> so there're no new tricky concurrency issues to reason about.
> 4) Values written to the write end can be reliably GC'd when readers
> go away, although recent GHC seems to be able to do this on the
> current implementation with -O2 on my simple tests.
> 5) While this is a big API change, I imagine the vast majority of
> users would only have to change a few type signatures and the Chan
> initialization action. An `OldChan` module could easily be implemented
> in terms of the new split version. Alternatively, a *Chan.Split module
> could be added, and the current Chan module defined in terms of it.
> So two weeks of discussion?
> Thanks all,
> Brandon
> _______________________________________________
> Libraries mailing list
> Libraries at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Libraries mailing list