[Haskell-cafe] Some thoughts on Type-Directed Name Resolution

AntC anthony_clayden at clear.net.nz
Fri Feb 3 14:37:49 CET 2012


Gábor Lehel <illissius <at> gmail.com> writes:

> 
> On Fri, Feb 3, 2012 at 10:30 AM, AntC <anthony_clayden <at> clear.net.nz> 
wrote:
> > 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 
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





More information about the Haskell-Cafe mailing list