
Gábor Lehel
On Fri, Feb 3, 2012 at 10:30 AM, AntC
You seem to be not alone in wanting some special syntax for applying field selectors (see other posts on this thread). H98 field selectors don't do
wrote: this,
they're just functions.
I'm puzzled why you want different syntax for field selectors. Can you give some intuition?
Here's my problems with allowing postfix application using dot for all functions.
Thank you Gábor for explaining this so clearly. I can see that mixing prefix and postfix style would be confusing. I suppose in other programming paradigms (like database access) record.field is regarded as 'atomic', not as function application. And under my proposal (or SORF or TDNR) it's atomic-ish, because the dot binds tighter than **even function application**. We already have in H98 field selection as function application. I'm keen not to break that, because then I can use dot notation on H98-style records. And I'm very keen that field selection (continue to) be equivalent to function application, precisely so that people who prefer prefix notation can "carry on regardless". Do people really write code with huge pile-ups of functions prefix upon prefix? Wouldn't that be confusing even when it's unidirectional? I've seen some examples in other threads mixing dot notation with function composition with user-defined operators built with a dot (like >.< ) and a sprinkling of parentheses. They were indeed unreadable, but frankly, I don't think that was purely down to the dot notation.
The first problem is that mixing prefix and postfix function application within the same line makes it harder to read.
I can see that. As you say, it's hopeless if readers have to start in the middle somewhere and work outwards, swerving to and fro. If binding-dot is just (reverse) function application, I can't stop people exploiting it for more than field selection, and some functions just 'feel' like fields. SPJ gave the examples of: customer.fullName -- fullName is a function to concat first ++ last shape.area -- polymorph area overloded for each shape And then there's: datetime.month -- calculate month from number-of-days format tuple.fst string.last name.middleInitial address.streetNumber polar.theta.arctan We're on the slippery slope! Where will it end? And now that I've found it, I so love: customer.lastName.tail.head.toUpper -- Yay! I notice that for prefix functions you do sometimes need a bit of trickery to deal with partial application and inconvenient order of parameters. Of course there's parentheses to help, but there's also a family of combinators, especially: ($) -- loose-binding function application (.) -- function composition So I'm going to take your post as a challenge: can we build a family of combinators for postfix style? The objective is to 'keep up the momentum' left to right. I've already been using one such: (.$) = flip ($) -- looks combinator-ish to me! (.$!) = flip ($!) -- strict version customer.lastName .$ tail .$ head .$ toUpper -- Yay.$!
The other problem is that, in order to make partial application convenient, you want to put your function's parameters in the order of least specific to most specific. If you want to make postfix application convenient, you have to do the reverse.
True-ish. I guess it depends how 'tight' you feel the function binds with it's least specific parameters. What's atomic?
For example, take the filter function from the Prelude:
filter :: (a -> Bool) -> [a] -> [a]
But for postfix function application, this latter order is the one you want:
[1..10].filter even is a lot more intuitive than even.filter [1..10]
Agreed. Easy. How do you like these?: [1..10] .$ filter even [1..10] .$ filter even .$ sum ^ 2 [1..10] .$ filter even .$ foldr (+) 0 ^ 2 I'm looking at those thinking 'Oh yes! foldr (+) 0 is atomic-ish'.
... You'll end up with some people preferring postfix notation and writing their functions one way, other people preferring partial application and writing their functions the other way, and a lot of frustration when people from one group want to use functions written by the other.
Yeah, like little-endians vs. big-endians.
I hope you'll agree that writing two versions of every function is not a satisfactory solution.
Absolutely! And we've a huge body of code defined in prefix form, we don't want to re-engineer that. And there's a whole body of mathematics/algebra/logic that uses prefix style.
To finally get around to the point:
All of this said, record.field is still the most readable, intuitive, and familiar syntax for selecting a field from a record that I know of. It would be nice to have it.
Indeed!
If we restrict this postfix notation to only selecting fields from records,
Would you like to include 'virtual' fields like fullName or area? Or fst or last or middleInitial?
So my preferred solution is:
- Selecting fields from records can be written (equivalently) using either prefix or postfix notation; - Everything else can be written only with prefix notation.
My second-choice solution is to not introduce postfix notation.
Noted. (And from the above, you won't expect me to agree.) I guess GHC HQ gets the final decision. Glad I'm not having to mediate. Thank you for raising the issue so cogently. AntC