About type sharing (mostly) and records (desugaring, mostly)

That bit’s unchanged since the '98 Report. Although there might be still around some people spatio-temporally contiguous with its authors, I very much doubt they’ll remember the intent at the time. We’d better try to interpret the words as given:

A constructor with associated field labels may still be used as an ordinary constructor; features using labels are simply a shorthand for operations using an underlying positional constructor.

So in purescript, that bit up to the semicolon does not hold: if your constructor is declared with field labels, you can only build values or access components using field labels; there’s no (visible) ‘underlying positional’ anything.

In SML, per my description in that earlier thread records are “not tied to any data type/not needing a data constructor prefix”. No ‘ordinary constructor’/no constructor at all. So again, you can only build or access record types using labels. There is a positional structure under the hood in the implementation; it’s abstracted away/you can’t access it directly from program code.

Hugs.Trex is very similar to SML: there’s no constructor [**] – that’s what it means by ‘anonymous’. (See my example decls above.) Some label fieldC might or might not appear in any particular record type. Even knowing that under the hood records are normalised to alphabetic sequence of field labels doesn’t help without knowing what other labels appear.

[**] Or you could argue there’s the same constructor Rec( ) for all record types. Then you’ll have to say it allows a variadic number of fields, with any combination of field names. So it ai’n’t a H98 constructor.

IOW without an actual proposal for records in front of us, we can’t presume in terms of “just another notational addtitive”. Just like (say) MultiParam Type Classes or FunDeps/Type Families or Scoped Type Variables can’t be ‘translated’ as just another notation for H2010: they express something beyond the semantics of H2010.

The H2010 report doesn’t help with what the meaning of (say) duplicate field labels ‘should be’. It merely says they’re not allowed in H2010 “A label cannot be shared by more than one type in scope.” The report isn’t trying to guess the future of Haskell. Heck it didn’t even describe de facto Haskell as supported by the two main compilers at the time it was published.

…hence the term “record syntax”. Your long list of record systems and their collective unsuitability for use with that syntax only excludes those systems - it isn’t a proof that a record system will never support Haskell 2010/1998 record syntax in a backwards-compatible way.

What that long list does show is just how stubbornly difficult it was (and still is) to find a solution to “the records problem” that’s:

  • suitable for Haskell, now and into the future,

  • and most people can at least tolerate, including people with prior experience with one or more of those systems from your long list.

I’m a lot puzzled by this response:

I mentioned three programming languages, of which two are very firmly in the Haskell stable. Here’s an example long list. (A reasonable sample, but by no means comprehensive. Note Pascal had records from the get-go 1970.) BTW I think records for non-functional languages are entirely suitable to compare. We don’t want mutable data structures; but we surely do want the ability to return a new data structure mostly copied from a previous ‘version’.

purescript's data syntax for declaring record structures is exactly the same syntax as Haskell’s. What it allows is same-named fields appearing in different datatypes – so it’s the semantics that’s different.

SML’s syntax if you’re going to put the record inside a data type with a constructor prefixing then is exactly the same syntax as Haskell’s. Again there’s no restriction on same-named fields. You can also use records stand-alone, again possibly with fields same-named as those inside a data.

Hugs.Trex was forced to use different syntax so that its records could co-exist with H98 data in the same module. I find that a dubious motivation – since Trex field names are in a different namespace vs H98. I think it could be arranged to choose module-wide H98 vs Trex semantics over the same syntax; including export/import of the different datatypes. (But you’d need namespace control to access Trex records from H98 semantics or v.v. – I have something of a prototype achieving that.)

As at early 2000’s a lot of people were voiciferous they could barely tolerate H98 records. A fair few of them were coming from SML. I see some have returned to SML. Anyhoo, many have abandoned Haskell.

That’s talking about design decisions up to the H98 standard.

I agree that as at H98 it would have been unwise to commit to a relatively unexplored design. 25 years have passed and … the field for design is still open. But nobody developed any robust designs, meanwhile a (by now) insurmountable fatberg of legacy code uses the allegedly ‘stopgap’ approach.

I find the emphasis on syntax curiously conservative for Haskell: most Haskell extensions deliberately also exploit additional syntax. Sometimes the old syntax can be treated as a special case of the new (MultiParam Type Classes take in H98 classes as a special case).

Yep all records proposals amount to that. The question is whether to expose the underlying positional access. And the clamour for labelled fields was precisely because that’s bad practice as soon as you have more than a couple of fields.

As a pedantic note, it actually isn’t the same syntax, because in PureScript you can do something like this (source):

author :: { name :: String, interests :: Array String }
author =
    { name: "Phil"
    , interests: ["Functional Programming", "JavaScript"]
    }

A PureScript declaration like data Person = Person { name :: String, interests :: Array String } may superficially look like Haskell, but it’s parsed differently — really it’s the equivalent of Haskell data Person = Person (String, [String]). Consult the differences from Haskell document for more information.

Alright, let’s look at how well your “insufferable-groaning” technique is working…


Other posts and threads by you about Haskell’s record syntax:

  • https://discourse.haskell.org/t/well-typed-blog-anonymous-or-large-records-with-overloadedrecorddot-and-overloadedrecordupdate/5939/2

  • https://discourse.haskell.org/t/haskell-records-compare-standard-ml/5933 (36 posts)

  • https://discourse.haskell.org/t/using-haskell-for-commercial-data-intensive-applications-name-clashes/4595 (4 posts)

  • https://discourse.haskell.org/t/the-evolution-of-ghc/4008/13

Progress towards solution in Haskell you would find satisfactory:

(...none!)

You really should consider finding another technique: your current choice just doesn’t seem to be having the desired result…

Like implementing more sophisticated behaviour?

Or combining records with Overlaps/FunDeps, to build projection and extension methods?

So I don’t just groan. I also document possible designs – as you yourself linked to earlier in the thread.

Hey thanks! I didn’t know that (so the syntax is more like SML’s). I looked at purescript a while back and saw only the more Haskell-like data decl. (Is that anonymous version a recent-ish change?) Yes I knew of the different parsing – I was focusing on the superficially similar syntax giving a different semantics.

Also I thought purescript's records were a thin veneer over Javascript. Is that still the case?

I don’t use PureScript, but I believe it’s always been like this. Insofar as I’m aware, this is precisely because they are just JavaScript records.

I also document possible designs […]

So here’s an idea for another one: since GHC will soon have a JS backend, maybe you can devise a way to bring JS’s record system into Haskell. But as you noted earlier in the thread, designs without working code don’t usually amount to anything (much like insufferable groaning).