[Haskell-cafe] How to implement this? A case for scoped record labels?

Claus Reinke claus.reinke at talk21.com
Tue May 26 20:00:02 EDT 2009


> I wonder if I am completely off here, but I am surprised that there is
> no progress on the scoped labels front. The Haskell wiki mentioned
> that the status quo is due to a missing optimum in the design space,
> but the same can be said about generic programming in Haskell and yet,
> GHC ships with Scrap your boilerplate. So we have to resort to type
> classes hacks instead of a proper solution. 

There are various implementations of extensible records available.
HList may have the best-supported versions and the most experience,
but essentially, they are simple enough to define that some packages
ship with their own variants (as long as there is no agreement on the
future of the language extensions needed to implement these libraries,
there won't be any standard library). See the links on the Haskell wiki
[1], though there are also newer entries on the GHC trac wiki [2,3].

The Haskell wiki page also points to my old first class labels proposal, 
which included a small example implementation based on Daan's 
scoped labels (there was a more recent implementation of Data.Record
which noone seemed interested in, and the fairly new Data.Label 
suggestion offers a workaround for the lack of first class labels, see [4]
for unsupported experimental versions of both).

The various accessor packages and generators might be a more
lightweight/portable alternative. In particular, they also cover the
case of nested accessors. And, going back to your original problem,
there is an intermediate stage between

    data BayeuxMessage = HandshakeRequest { channel :: String , ... }
         | HandshakeResponse { channel :: String, successful :: Bool, ... }
         | ...

and 

    data HandshakeRequest = HandshakeRequest { channel :: String , ... }
    data HandshakeResponse = HandshakeResponse { channel :: String,
        successful :: Bool, ... }
    ...

    data BayeuxMessage = HSReq HandshakeRequest
        | HSRes HandshakeResponse
        ...

namely

    data HandshakeRequest = HandshakeRequest { ... }
    data HandshakeResponse = HandshakeResponse { successful :: Bool, ... }
    ...
    data BayeuxMessage = HSReq{ channel :: String, request :: HandshakeRequest }
        | HSRes{ channel :: String, response :: HandshakeResponse }
        ...

Generally, you'll often want to use labelled fields with parameterized
types, eg

    data NamedRecord a = Record { name :: a, ... }
    type StringNamedRecord = Record String
    type IntNamedRecord = Record Int

and, no, I don't suggest to encoded types in names, this is just an
abstract example;-) Mostly, don't feel bound to a single upfront design,
refactor your initial code until it better fits your needs, as you discover
them.

Hth,
Claus

[1] http://www.haskell.org/haskellwiki/Extensible_record
[2] http://hackage.haskell.org/trac/ghc/wiki/ExtensibleRecords
[3] http://hackage.haskell.org/trac/ghc/ticket/1872
[4] http://community.haskell.org/~claus/




More information about the Haskell-Cafe mailing list