[Haskell-cafe] A practical Haskell puzzle

Yitzchak Gale gale at sefer.org
Mon Feb 28 08:43:10 CET 2011


You have written a large software system in Haskell. Wishing to
play to Haskell's strength, you have structured your system
as a series of composable layers. So you have data types

Layer1, Layer2, ...

and functions

layer2 :: Layer1 -> Layer2
layer3 :: Layer2 -> Layer3
...

etc.

Of course you'll want to be able to run any range
of the layers separately, at least for testing and debugging
purposes if not for the functionality itself.

So your UI module (command line or whatever) that launches
your application provides a data type

data Layers = Layers Int Int

that indicates which layers to run, and functions

deserialize1 :: L.ByteString -> Layer1
deserialize2 :: L.ByteString -> Layer2
...

serialize1 :: Layer1 -> L.ByteString
serialize2 :: Layer2 -> L.ByteString
...

etc.

Now you need a function

runLayers :: Layers -> L.ByteString -> L.ByteString

so that the effect is for example

runLayers (Layers 4 6) = serialize6 . layer6 . layer5 . deserialize4

Typically there could be 20 or 30 layers, so writing out each
case could result in hundred of boilerplate definitions for runLayers.
Scripting the generation of all that boilerplate, e.g. using TH,
doesn't seem very attractive either. On the other hand, it seems
silly to have to use super-advanced type olegery for such
a trivially simple yet centrally important component of the
system.

What is the best way to write runLayers? Feel free to change
the details of the above design, as long as it meets the
functionality requirements expressed.

Regards,
Yitz



More information about the Haskell-Cafe mailing list