PROPOSAL: Include record puns in Haskell 2011

Hello, I'd like to propose that we add record punning to Haskell 2011. I think that this is a useful feature which makes working with record fields easier, and reduces clutter in definitions, both in patterns and expressions. Furthermore, this features has been implemented in GHC for a long time (it used to be in Hugs too, once) and we've had plenty of time to iron out dark corners in the design. Thoughts, objections, suggestions? -Iavor

I'd like to propose that we add record punning to Haskell 2011.
Can you be more specific? Do you propose to re-instate punning exactly as it was specified in Haskell 1.3? Or do you propose in addition some of the newer extensions that have been recently implemented in ghc (but not other compilers), such as record wildcards? Regards, Malcolm

On Tue, Feb 23, 2010 at 07:07:30PM -0800, Iavor Diatchki wrote:
I'd like to propose that we add record punning to Haskell 2011.
Thoughts, objections, suggestions?
I have a feeling I'm in the minority, but I find record punning an ugly feature. Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely. Thanks Ian

Ian Lynagh wrote:
I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
I agree with Ian. Groetjes, Martijn.

On 02/24/10 13:40, Martijn van Steenbergen wrote:
Ian Lynagh wrote:
I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
I agree with Ian.
I tend to agree. I don't mind if a few files that use a ton of label-operations are marked with NamedFieldPuns and use that feature a lot. But, funnily, if it were put in the standard then it would be enabled in un-marked source files, and then I personally wouldn't like it as much. (Any decision is acceptable to me though.) -Isaac

| >> we implicitly get | >> f :: T -> Int | >> which punning shadows with | >> f :: Int | >> whereas I generally avoid shadowing completely. | > | > I agree with Ian. | | I tend to agree. I originally had field puns in GHC, and then took them out when Haskell 98 removed them, after a discussion very like this one. I put them back in because some people really wanted them. Actually GHC has three separate extensions to do with named fields: field disambiguation (Section 7.3.14) field puns (Section 7.3.15) field wildcards (Section 7.3.16) Look here http://www.haskell.org/ghc/docs/latest/html/users_guide/syntax-extns.html#di... Opinions differ. I'm rather with John: let the programmer choose, rather than enforcing a style in the language. For punning, the programmer can certainly choose on a case by case basis. If you use Haskell 98's existing syntax, there is no change to the semantics if you switch on field puns: data T = C { f :: Int } foo (C {f = x}) = ... -- No punning bar (C {f}) = ... -- Punning It would help this discussion if someone created a ticket to explain the actual proposal, so that we are all discussing the same thing. Simon

Isaac Dupree
writes: On 02/24/10 13:40, Martijn van Steenbergen wrote: Ian Lynagh wrote:
I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
I agree with Ian.
I tend to agree.
<snip>
-Isaac
(I know how you're always looking for things to take out of Haskell ...) I can see the ugliness of having a name with two incompatible types (especially in the same scope). I wonder: if a programmer from Mars landed into Haskell a la GHC 2010 (that is, unburdened by history back to v1.3), wouldn't it be the scare-quotes 'implicit' field selector that seems the odd man out? After all, the program text declares { f :: Int }, and in all uses of the field label apart from selecting, it _is_ an Int. Where does this function thing come from? By the way, it seems you can arrive at the same level of confusion like this (declared in a distinct scope):
f (C { f }) = f -- f :: T -> Int
- Anthony

(I know how you're always looking for things to take out of Haskell ...)
I can see the ugliness of having a name with two incompatible types (especially in the same scope).
That's a good point, but even if not totally logical I think the automatic "Rec -> X" function is more important than the X meaning. Functions are more resistant to change (for instance, I changed from String to Data.Text but could keep the old recString as a function when the field named changed), so while I think the sugar to bring names into scope is handy, I think functional access should be encouraged as the "main" way to do it. The whole tension between syntactic convenience of pattern matching and the flexibility of function accessors in the face of change is kind of unfortunate. It mirrors the OO dilemma of x.y vs. x.y(), which some OO languages do away with altogether. So I'd want to go the other way by making functional access and update more convenient and prominent rather than syntactical. Maybe we could have a little extension of view patterns where "f (field ->) = y" is transformed to "f (field -> field) = y". It's still a shadow, but at least now it works with any function. It might be nice to do the same with update functions, but those aren't even generated automatically (anyone got a generics thing that cranks those out?).

Evan Laforge
That's a good point, but even if not totally logical I think the automatic "Rec -> X" function is more important than the X meaning.
[...]
It might be nice to do the same with update functions, but those aren't even generated automatically (anyone got a generics thing that cranks those out?).
See my other post for a way of doing both of these. -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

Anthony Clayden
(I know how you're always looking for things to take out of Haskell ...)
I can see the ugliness of having a name with two incompatible types (especially in the same scope).
Granted.
After all, the program text declares { f :: Int }, and in all uses of the field label apart from selecting, it _is_ an Int.
It's not; it's shorthand for something else (a bare f in a programme doesn't get you an Int -- which one would it be?). One of the nice things about Haskell is that if you know the name of something and the something has a type, then you know something about all the possible values it can have. In current Haskell, f here isn't a name in that sense, which is a big pity (you can't pass a field label as an argument to a function, for example).
Where does this function thing come from?
It comes (as you imply) from it's use as a field selector. I'd say that (and field update) were its primary uses. It would be far better to make field labels proper first-class entities that have a translation into lambda calculus (or System F as you will). I would much rather see field labels having their own type, so that data F t = F {f:: H t} declares the type F, the constructor F and a name f:: Selector (F t) (H t) the language definition needn't make whatever is inside Selector directly visible to the programmer, but we can think of it as secretly being a pair of functions ((F t -> H t), (H t -> F t -> F t)) Now f x would be an overloaded meaning of application¹. And r{f=g} would be shorthand for (magic-snd f g r), where magic-snd is just snd made suitable for application to Selector. (Frankly, I'd rather lose the r{f=g} syntax and provide an operator that accesses the second part of f so that it can be applied as a function, eg (f←g) r. This (f←g) would then also be a first class function.) Doing it this way would get rid of the peculiar multiple type issue, make it completely clear what field labels translate to and give us field labels as proper first class entities. [1] as it currently is, and I'm not suggesting allowing general overloading of application, but at least this way we'd know what f was -- Jón Fairbairn Jon.Fairbairn@cl.cam.ac.uk

On Wed, Feb 24, 2010 at 06:23:39PM +0000, Ian Lynagh wrote:
On Tue, Feb 23, 2010 at 07:07:30PM -0800, Iavor Diatchki wrote: I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
I can see the thinking here, but I don't like for the language to try to enforce 'style' or make decisions based on it. I think it is more in the spirit of haskell to provide multiple mechanisms when it makes sense and let the users figure out what works for them stylistically. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

On 24 Feb 2010, at 18:52, John Meacham wrote:
On Wed, Feb 24, 2010 at 06:23:39PM +0000, Ian Lynagh wrote:
On Tue, Feb 23, 2010 at 07:07:30PM -0800, Iavor Diatchki wrote: I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
I can see the thinking here, but I don't like for the language to try to enforce 'style' or make decisions based on it. I think it is more in the spirit of haskell to provide multiple mechanisms when it makes sense and let the users figure out what works for them stylistically.
The problem though, unless I'm misunderstanding, is that you *must* enforce one or other convention here. Either you force everyone who's style is to never shadow things to do so because of this language feature, or you remove the language feature and trample on the other crowd. For what it's worth, I'd side with Ian on this one. Bob

On Wed, Feb 24, 2010 at 06:54:44PM +0000, Thomas Davie wrote:
The problem though, unless I'm misunderstanding, is that you *must* enforce one or other convention here. Either you force everyone who's style is to never shadow things to do so because of this language feature, or you remove the language feature and trample on the other crowd.
Hmm? I don't see how this language feature forces shadowing any more than allowing shadowing anywhere else in the language. It is not proposed that field punning replace the previous mechanism for assigning or pulling values from fields, just that it be added as an option. Just as it has always been an option to shadow variables in do notation. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

On 24/02/10 18:23, Ian Lynagh wrote:
On Tue, Feb 23, 2010 at 07:07:30PM -0800, Iavor Diatchki wrote:
I'd like to propose that we add record punning to Haskell 2011.
Thoughts, objections, suggestions?
I have a feeling I'm in the minority, but I find record punning an ugly feature.
Given data T = C { f :: Int } we implicitly get f :: T -> Int which punning shadows with f :: Int whereas I generally avoid shadowing completely.
While I agree with these points, I was converted to record punning (actually record wildcards) when I rewrote the GHC IO library. Handle is a record with 12 or so fields, and there are literally dozens of functions that start like this: flushWriteBuffer :: Handle -> IO () flushWriteBuffer Handle{..} = do if I had to write out the field names I use each time, and even worse, think up names to bind to each of them, it would be hideous. There are reasons to find this distasteful, yes, but I think the alternative is much worse. I'm not proposing record wildcards (yet) *cough* labelled-field wildcards, but punning is a step in the right direction. Cheers, Simon

On Wed, Feb 24, 2010 at 08:50:42PM +0000, Simon Marlow wrote:
On 24/02/10 18:23, Ian Lynagh wrote: While I agree with these points, I was converted to record punning (actually record wildcards) when I rewrote the GHC IO library. Handle is a record with 12 or so fields, and there are literally dozens of functions that start like this:
flushWriteBuffer :: Handle -> IO () flushWriteBuffer Handle{..} = do
if I had to write out the field names I use each time, and even worse, think up names to bind to each of them, it would be hideous.
There are reasons to find this distasteful, yes, but I think the alternative is much worse.
I'm not proposing record wildcards (yet) *cough* labelled-field wildcards, but punning is a step in the right direction.
Yes. I too have had this issue with jhc and am a big fan of GHC's field wildcards. It is motivation enough for me to require a newer version of ghc for compiling jhc. I'd support field wildcards in 2011, but would understand if people thought it was too soon. John -- John Meacham - ⑆repetae.net⑆john⑈ - http://notanumber.net/

Simon Marlow wrote:
While I agree with these points, I was converted to record punning (actually record wildcards) when I rewrote the GHC IO library. Handle is a record with 12 or so fields, and there are literally dozens of functions that start like this:
flushWriteBuffer :: Handle -> IO () flushWriteBuffer Handle{..} = do
if I had to write out the field names I use each time, and even worse, think up names to bind to each of them, it would be hideous.
What about using field names as functions? flushWriteBuffer h@(Handle {}) = do ... buffer h ... Of course, you always have to drag h around. Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com

Hello,
In order to keep the discussion structured I have created two tickets
in the haskell-prime trac system
(http://hackage.haskell.org/trac/haskell-prime):
* Proposal 1: Add pre-Haskell'98 style punning and record
disambiguation (ticket #136)
* Proposal 2: Add record-wildcards (ticket #137)
I decided to split the two into separate tickets because, at least in
my mind, there are different things that we might discuss about the
two, and also they make sense independent of each other (although
record wildcards without punning might be a bit weird :-).
I think that both proposals are worth considering for Haskell 2011
because there are situations where they can significantly improve the
readability of code involving record manipulation. I disagree with
the stylistic issues that were brought up in the discussion because I
do not believe that variable "shadowing" should be avoided at all
costs: at least for me, avoiding shadowing is a means to an end
rather then an end in itself. In the case of record puns, I think
that the clarity of the notation far surpasses any confusion that
might be introduced by the shadowing. Furthermore, as other
participants in the discussion pointed out, the proposed features are
orthogonal to the rest of the language, so their use is entirely
optional.
-Iavor
On Fri, Feb 26, 2010 at 2:59 AM, Heinrich Apfelmus
Simon Marlow wrote:
While I agree with these points, I was converted to record punning (actually record wildcards) when I rewrote the GHC IO library. Handle is a record with 12 or so fields, and there are literally dozens of functions that start like this:
flushWriteBuffer :: Handle -> IO () flushWriteBuffer Handle{..} = do
if I had to write out the field names I use each time, and even worse, think up names to bind to each of them, it would be hideous.
What about using field names as functions?
flushWriteBuffer h@(Handle {}) = do ... buffer h ...
Of course, you always have to drag h around.
Regards, Heinrich Apfelmus
-- http://apfelmus.nfshost.com
_______________________________________________ Haskell-prime mailing list Haskell-prime@haskell.org http://www.haskell.org/mailman/listinfo/haskell-prime
participants (13)
-
Anthony Clayden
-
Evan Laforge
-
Heinrich Apfelmus
-
Ian Lynagh
-
Iavor Diatchki
-
Isaac Dupree
-
John Meacham
-
Jon Fairbairn
-
Malcolm Wallace
-
Martijn van Steenbergen
-
Simon Marlow
-
Simon Peyton-Jones
-
Thomas Davie