Records in Haskell

AntC anthony_clayden at
Fri Mar 2 09:49:37 CET 2012

Gábor Lehel <illissius <at>> writes:

> ...
> ... My main complaint against DORF is
> that having to write fieldLabel declarations for every field you want
> to use is onerous. If that could be solved, I don't think there are
> any others. (But even if it can't be, I still prefer DORF.)

Thank you Gábor, I understand that 'complaint'.

I have been trying to keep the design 'clean': either the module is totally 
DORF, or it's totally H98.

But I've also tried to conform to H98 style where possible. So:
* DORF field selectors are just functions, like H98 field selector functions.
* dot syntax is just reverse apply, so could be used for H98 selectors
* pattern syntax still works, and explicit record constructor syntax
       (relying on DisambiguateRecordFields)
* record update syntax is the same (but with a different desugarring)
* record decl syntax is the same
      (but desugars to a Has instance, instead of a function)

There have been several suggestions amongst the threads to mix H98-style 
fields with DORF-style records (or perhaps I mean vice-versa!):
* We'd need to change the record decl syntax to 'flag' DORF fields (somehow).
* H98 fields desugar to monomorphic field selector functions, as usual.
  So if you have more than one in scope, that's a name clash.
* DORF fields desugar to Has instances.
  (providing you've declared the fieldLabel somewhere)
  Perhaps we could take advantage of knowing it's DORF
   to pick up the field type from the fieldLabel decl?

I think you could then 'mix and match' DORF and H98 fields in your expressions 
and patterns (that was certainly part of my intention in designing DORF).

There's one difficulty I can see:
* record update would have to know which sort of field it was updating in:
    r{ fld = expr }
  If `fld` is DORF, this desugars to a call to `set`.
  If H98, this code stands as is.
What about:
    r{ fldH98 = expr1, fldDORF = expr2, fldH983 = expr3, fldDORF4 = expr4 }
I think:
* for DORF updates `set` can only go one field at a time,
  so it turns into a bunch of nested `set`s
  (One for fldDORF, inside one for fldDORF4.)
* for H98 it can do simultaneous, so in effect we go:
  let r' = r{ fldDORF = expr2, fldDORF4 = expr4 }   -- desugar to nested
    in r'{ fldH98 = expr1, fldH983 = expr3 }

Remaining question: how do we tell a DORF field from a H98,
at the point of the record update expression?
What is the difference? Find the field selector in the environment from the 
- if monomorphic, it's H98
- if overloaded, it's DORF

But! but! we don't know its type until the type inference phase.
Yet we need to desugar the syntax at the syntax phase(!)

Suggestions please!

Also an obfuscation factor: perversely, the record type and field labels might 
have been exported, but not the selector function.


More information about the Glasgow-haskell-users mailing list