patch applied (haskell-prime-status): add ""Make $ left
associative, like application"
niklas.broberg at gmail.com
Wed Apr 23 16:42:02 EDT 2008
When I first saw this thread, my gut response was "Aw gawds no, don't
touch my $ !!" I love $, I use it all the time, it really helps making
code more readable and more nicely structured. I would really hate for
someone to take that away from me.
So when I came across this:
> > This wouldn't work, you'd have to rewrite it as:
> > withSomeResource foo .
> > withSomeOtherThing bar .
> > yetAnotherBlockStructured thing $ ...
> it is very inconvenient - we should use either . or $ depending on
> that it's last block or not. imagine all the changes when editing the
... my initial response to it was yeah, Bulat is right, that's rather
inconsistent, and it would mean a lot of changes when editing (and
it's ugly too!).
But then I started questioning my own motives. What changes would that
be? Changing a . to a $ if I decided to remove the previous last piece
of the "pipeline"? Doesn't seem too hairy, and I have to do far worse
than that already when refactoring. Inconsistent? Doesn't it actually
make perfect sense that the actual application of the "pipeline" of
functions to some value is handled differently? Like Cale said,
wouldn't it actually be a Good Thing that we treated these things as
composition chains instead of application chains? And I could no
longer defend my own position, and so I started thinking for real.
Refactoring doesn't become harder with this suggestion - it becomes
easier in general, just as Dan points out in #1. And I know I've been
bitten by his #2 a bunch of times, even if I haven't realized the
source of the problem until I read this thread. It's messy having to
use a lot of parenthesis just because some argument to a function
isn't the last one, and I've found myself wishing for a way to get rid
of them. I know I have at times refactored my function definitions,
switching their arguments around just to get the one that would need
the parenthesis to be the last one.
So I dug through some of my code, picking large modules at random. As
I said I use $ *a lot*, anywhere that I can get away with it. In the
first 10 modules I looked at, I found one (1) place where I would need
to change a $ to a . to make it work. So I went to look at a bigger
module, and in what is possibly my largest self-contained module (1800
loc including comments) I had 211 uses of $, and I would have had to
change 23 of them into . instead to make it work with a
left-associative version. All the ones where the left operand is just
a function (like return) will still work. All the ones that are
followed by a '\x -> ...' will still work. All the ones followed by a
'do ...' will still work. On the other hand, I found 10 places where I
could immediately have gotten rid of some extra parentheses, and that
just by searching for uses of fmap in the code!
It should be said though that changing the associativity of $ doesn't
make all code nice and clean. Consider for instance
f (g (h x)) (k y)
We could change that into one of
f $ g (h x) $ k y
f (g $ h x) $ k y
but not get rid of the parenthesis altogether, i.e. uses of $ for
different applications won't mix. But with right-associative $, the
second one would be our only option, so at least we're no worse off
than before, and perhaps it could be argued we are better off (in this
kind of situation).
I think it is reasonable to look closely at the motivations for
wanting to retain the $ as is. Looking through this thread, I can find
only a single complaint raised (albeit an important one), namely
backwards compatibility. Yes, such a change would likely break quite a
few my modules. But like Cale, I would never have expected H' to be
fully backwards compatible with H98, and thus there would have to be
some way to migrate anyway. This one seems pretty simple, just let the
old Prelude be Haskell98.Prelude and import that in old code. Of
course changes that break backwards compatibility should not be made
frivolously, but I find it hard to buy having only that as an argument
for a change that otherwise seems highly reasonable.
We live in a beautiful statically typed world. If the proposed change
was such that existing code would still compile, but with a different
behavior, it would be really dangerous. That's clearly not the case
here, there's no way that code that uses $-chaining would still
compile if the associativity was changed, and any other use of $ would
still compile and work as before. The type checker is there to help
us, and it's literally a moment's work to clean up existing code to
meet these standards. (And it's even faster to import
Haskell98.Prelude if you're lazy).
So come on, give me an argument for why $ should be right-associative
instead of complaining about broken code (that I argue won't break
even half as bad as some of you would have it). Is there really no
reason at all why right-associative is to be preferred over
left-associative? And if there is, why don't we hear it? Are you truly
arguing this because you think there's a problem with left-associative
$, or are you simply arguing because you want to stay with what you're
"The ability to think differently today from yesterday distinguishes
the wise man from the stubborn." - John Steinbeck
ps. Though to be honest I really don't see why we don't simply add
another operator instead of changing an existing one... :-)
More information about the Haskell-prime