Record syntax

As a community, we're at an impasse about record systems - it seems that the bikeshed's going to be painted _|_. On the one hand, it's possible to encode our own record systems in the language with careful use of type functions or fundeps. On the other hand, there's neither syntactic support nor compiler support to make our records run efficiently.

We can't provide compiler support and we can't bake in syntax for one specific system at this stage, but perhaps we can provide overloaded syntax in the same vein as GHC's string literal support or numeric literals? Or better yet, something akin to GHC's rebindable syntax, so that we don't even force a type class?

What do we need to supply as a minimum? I think the two operations we absolutely have to support are field access and record update. Each of these needs to call some specified function with a certain amount of information to support a reasonable range of record systems. Some of this information is type-level information - we need a type-level representation of labels so the type class mechanism can look up the appropriate operation.

So suppose we borrow the field access syntax from TDNR, but translate "record.field" to "access record labelProxy" where labelProxy is something like undefined :: field. We can then let a user-selected library define access, without actually fixing its type. What we have fixed is that access has to be able to work out its return type from the types of the record and the label proxy. With the right definitions put in scope, it wouldn't be too difficult to make the current scheme work. The generality of the TDNR scheme wouldn't apply, but its special case for records would given an appropriate set of instances and an appropriate definition of access as well. This means we can achieve backwards compatability thus far. It also ought to be possible to plug in record systems based on something like HList, or even something completely ad hoc.

Record update would work similarly - we would need to call a function to do single-field updates, something like "update record labelProxy value". We could even reuse the existing update syntax, or failing that a minor lexical modification of it to mark it out as unique.

Namespacing is an issue. I don't propose that we actually use 'access' and 'update' as names because they're rather obvious candidates for someone else to use, so suitably obfuscated equivalents need to be picked. Similarly, we really need the types corresponding to labels to have their own chunk of namespace (and perhaps their own kind?), whether it's Label_fieldname or (my preference) involves a magic character at the start.

Ideally, a new record system would also be backwards-compatible with existing record declarations. Short of manually writing instances, I think the only way we can achieve this is to make use of Template Haskell, feeding declarations of records into a named function that can define the appropriate instances for the record system in use. The field accessor functions can then all be translated into new style accesses, and field patterns in case statements would need a similar translation. Understandably, this might be considered too hacky for an initial implementation and it would definitely want its own LANGUAGE tag separate from the syntax above. I do believe having the option is a major plus however.

I don't know if we'll ever pick a new record system for standardised Haskell, but I believe this proposal offers a way forward from the barely tolerable situation we have at present. Not only that, but it should also make it less of a blow should a record system be standardised that doesn't suit a given project - so long as compilers support rebindable record syntax, having a default does no harm.