As the shepherd for this proposal, I’m happy to say that the GHC Steering Committee has, finally, come to a conclusion: we accept the proposal, subject to final revisions (see “What happens next”), with some additional specifics about syntax (see “Our conclusion”).

The process

  • The proposal is entirely about syntax; and specifically about introducing the form r.x for record field selection. No changes

    to the underlying type system, or any other aspect of the language, are proposed. The original proposal was more elaborate but was simplified to focus on the essentials.

  • Records constitute a particularly rich and complex design space, and elicit an unusually broad range of opinions. This proposal attracted over 500 comments, a record for a GHC proposal.

  • This diversity of opinion was reflected in the committee, as you can see if you read the committee’s email discussion.

One possible reaction to a diversity of opinion is to do nothing and wait for clarity to emerge. That is often the right choice, but not (I believe strongly) in this case. We have waited a long time already — I have been engaged in debate about this topic for over two decades — and I think it’s time to decide something. The details matter, though. So we did this:

  • We put together a list of choices, which you can find here, including “reject” (which some members argued for). Members were encouraged to add any choices they felt were missing, and clarify any choices on offer so that everyone understood them. (A note about the Elm “naked selector” possibility, where naked selectors are ordinary functions: no member asked to add this choice.)
  • Once that discussion had concluded, I called a vote. We voted using the Condorcet algorithm to take account not only of people’s top choice, but of the ordering of their choices. This process allowed us to express our preferences, while respecting the fact that others might have a different view.

Our conclusion

Happily, there was a clear winner: choice (C2a) beats every other options by 7:4 or more. It is as follows:

  • The form .x or .x.y.z is a new lexeme, called a “naked selector”.

  • A naked selector is illegal, except when enclosed in parens, (.x.y.z) means (r -> r.x.y.z); that is, it is a record selector. So you can write map (.x) rs to map a selector over a list of records.

  • “r.” with no immediately-following “x” is two lexemes “r” and “.”, i.e function composition. So (r. x) means (r . x).

  • The form r.x (with no spaces on either side of the dot) is not treated as a naked record selector; instead it is treated as an atomic expression, very like a qualified name M.x. So f r.x means f (r.x).

  • The same holds if r is replaced by a parenthesised expression. So f (g 3).x means f ((g 3).x). Or, in general, any atomic expressions, such as [a,b].


f r.x        means       f (r.x)
f M.n.x      means       f (M.n.x)
f M.N.x      means       f (M.N.x)
f r .x       is illegal
f (g r).x    means       f ((g r).x)
f (g r) .x   is illegal

As you can see, it’s a pretty conservative choice. We spent a lot of time discussing more expressive options. Especially, we considered naked selectors as postfix operators, so that

  f .x .y .z   means   f.x.y.z
  f .x 3 .y 4  means   ((f.x) 3).y 4

allowing whitespace between the selectors. You can see a number of variants of this idea among the choices the committee discussed. But we chose a more conservative path for now. By making naked record selectors illegal (except in parens) we leave those possibilities open for the future, as we get more experience. (This is one reason for not adopting Elm’s use of naked record selectors without parens.)

Another principle was that it should be possible to replace a variable with the expression it is bound to, so that wherever you can write r.x you can also write (f 3).x.

What happens next

I’d like to invite the authors to update their proposal to incorporate (C2a), and in particular

  • To write out the changes to the grammar, especially how to deal with specifying aexp2.x (see Note 5)
  • To address the question of what happens if a field name is an operator (see Note 6)
    data T = MkT { (&&&) :: Int -> Int, ... }

Then the committee can do a final review and sign it off.

Many people have contributed to this conversation — thank you! The fact that we don’t all agree 100% is OK — people’s judgements differ. Many, perhaps most, people (myself included) would have made a different choice left to themselves. But we have a way to resolve such differences of judgement, which we have executed, and I respect the conclusion.

Read More

ترك الرد

من فضلك ادخل تعليقك
من فضلك ادخل اسمك هنا