[Haskell-cafe] What's the deal with Clean?

Ketil Malde ketil at malde.org
Fri Nov 6 02:45:02 EST 2009

Duncan Coutts <duncan.coutts at googlemail.com> writes:

>> The "build operation" part often ends up a bit gross, but I have a plan
>> for that which I hope to come back to later on.
> Yes, they're not good for construction atm. The Builder monoid from the

I've used that a bit, but that's not what I'm talking about.
Serializing and deserializing to/from bytestrings is sometimes
complicated, but usually straightforward enough.

The operation in between is what is giving me headaches.  Basically, I
have a bunch of command line options - filter on this, modify on that,
produce some kind of output to some file - that must be interpreted in
order to produce a combined filter/modifier processing. 

The pipeline looks something like this:

  readFoo :: IO [Foo]
  process :: [Foo] -> IO [Foo]
  writeFoo :: [Foo] -> IO ()

The hard part is how to elegantly construct the "process" part.
If it were just filtering or modifications, it could be a pure
function.  The complexity comes from sometimes needing to split off
some output to some file.  

Currently, I'm opening handles in advance, and processing one Foo at a
time, writing it to the correct handles, and finally closing handles
when done.  This is a rather pedestrian approach.

I'm now considering defining

    branch :: ([Foo] -> IO ()) -> [Foo] -> IO [Foo]
    branch iop fs = do forkIO (iop fs)
                       return fs

Which, if I understand correctly, would allow me to write

   process = filterM this >>= mapM that 
             >>= branch (writeBar . map foo2bar) >>= filterM theother

So - is this a good way to approach it?  I feel slightly queasy about
using concurrency for this, although I think it'll work well in
practice.  It is very important that this is lazy - the list of Foos can
be larger than available memory, so one risk is that one thread might
run off with the list of Foos with the other trailing far behind,
leading to increased memory use. Previous experience seems to indicate
that the 'head' thread will be slowed by disk/memory and allow the
trailing threads to keep up.

I do have a nagging feeling that this could be solved more elegantly
with arrows or a lazy writer monad, or something else that I don't know
enough about. I'd be happy to hear any suggestions.


PS: I probably need to catch the threadID, and wait for all threads to
finish as well.  This is left as an excercise for the writer. :-)
If I haven't seen further, it is by standing in the footprints of giants

More information about the Haskell-Cafe mailing list