Better Records was Re: [Haskell-cafe] Type Directed Name Resolution

Evan Laforge qdunkan at gmail.com
Thu Nov 11 22:56:29 EST 2010


> This motivated my original reply this post. The trouble is, what
> constitutes better records? There are as many views as users of Haskell, I
> bet.
>
> My main motivation is:
>
> As mentioned in my original post: better name space management.
>
> Surprisingly enough, I find the current record system is quite usable, bar
> one feature. My particular use case: commercial applications make heavy use
> of records (in connection with relational databases) and name clashes are
> inevitable.

I too would like better records, and I too find them usable if not
ideal in their current form.  They wind up being doubly qualified,
e.g. 'State.state_blocks st' and can be quite verbose.  Consider an
extreme case:

set_track_width view_id width = do
    track_views <- modify_at "set_track_width"
        (Block.view_tracks view) tracknum $ \tview ->
            tview { Block.track_view_width = width }
    update_view view_id (view { Block.view_tracks = track_views })

update_view view_id view = modify $ \st -> st
    { state_views = Map.adjust (const view) view_id (state_views st) }

What I am actually *doing* here, is:

state.get_view(view_id).tracks[tracknum].width := width

Part of the difference is that updating data is fundamentally more
idiomatic in an imperative language, and it's true this is a rare
example (modify_at updates a list at an index, ignore that :P).  But
the fact is that the difference between what I write and what I mean
is reaching almost comical java-like levels.

'modify $ \st -> st { State.state_x = f (State.state_x st) }' is quite
common, and modifying two levels deep also happens (which requires an
auxiliary function to be readable).  And the 'f' is buried in the
middle of a bunch of boilerplate.

> - light weight records (c.f. ML)

I actually don't feel a lot of need for this... if I want a
short-lived data structure I just use a tuple.  I use records when
they are being passed through multiple functions, and at that point
I'm probably going to at least a type synonym, and then we're back to
heavy-weight, right?

The only place I can think of where light-weight records would be
handy is simulating keyword args... but even then it seems hardly a
burden to declare a datatype for it, and it gives you a place to put
documentation.  Any other uses out there?

> - first class labels (accessors and setters)

I would love this.  I don't even think accessors is really the
problem, they compose nicely as just functions even if they are a
little wordy.  It's update that's the killer.  The reason I say it's
bearable even though it can be quite verbose is that update (at least
in my programs) is uncommon enough that I can factor all common
updates into functions and then just call those.

> - extensible records
> - sub-typing

Unlike the above things which make it more convenient to write the
same code, it sounds like these things would actually let you write
new kinds of code.  However, I don't really feel like I'm missing
that.  Maybe it's a "blub" problem?  Are there some examples of cool
things you could do with either of the above that you can't do
(conveniently) without?

In fact, given that updates seem to be the only thing I care about,
maybe I'd be made almost as happy by a functional refs library.  There
are several competing implementations on hackage but AFAIK none are
considered universal and standard (none are in HP, for instance).

> http://research.microsoft.com/en-us/um/people/simonpj/Haskell/records.html
>
> "Haskell lacks a serious record system. (The existing mechanism for named
> fields in data types was always seen as a stop-gap measure.)"
>
> isn't it about time this changed?

I sure think so :)


More information about the Haskell-Cafe mailing list