
Hi. I'm working through Real World Haskell, and although it's going well (I just finished the exercise to write a glob matcher without using a regex library, and I'm pleased as punch), I keep seeing the ($) operator, and I'm not sure I understand its use. If the book explains it, I've been unable to find it. Empirically, it seems like: a $ b c d e f .. is equivalent to .. a (b c d e f) But is that it's only purpose? To placate the LISP haters by removing parentheses? (1 +) 2 does the same thing as (1 +) $ 2, and has the same type. Am I missing something? Thanks, John -- "There is no way to peace; peace is the way"

Am Samstag, 24. Januar 2009 20:37 schrieb John Hartnup:
Hi.
I'm working through Real World Haskell, and although it's going well (I just finished the exercise to write a glob matcher without using a regex library, and I'm pleased as punch), I keep seeing the ($) operator, and I'm not sure I understand its use. If the book explains it, I've been unable to find it.
Empirically, it seems like: a $ b c d e f .. is equivalent to .. a (b c d e f)
Indeed. ($) is the function application operator, f $ x = f x , so a $ b c d e f is equivalent to a (b c d e f) and a $ b c $ d e f to a (b c (d e f)).
But is that its only purpose? To placate the LISP haters by removing parentheses?
More or less. Although the idea was more to enhance readability than placating LISP haters :) It's also handy to pass to some higher order functions, although offhand I can't think of any situation where you couldn't pass id instead of ($).
(1 +) 2 does the same thing as (1 +) $ 2, and has the same type.
Am I missing something?
Thanks, John

On Sat, Jan 24, 2009 at 07:37:29PM +0000, John Hartnup wrote:
Hi.
I'm working through Real World Haskell, and although it's going well (I just finished the exercise to write a glob matcher without using a regex library, and I'm pleased as punch), I keep seeing the ($) operator, and I'm not sure I understand its use. If the book explains it, I've been unable to find it.
Empirically, it seems like: a $ b c d e f .. is equivalent to .. a (b c d e f)
But is that it's only purpose? To placate the LISP haters by removing parentheses?
(1 +) 2 does the same thing as (1 +) $ 2, and has the same type.
Am I missing something?
More generally, in a language with first-class and higher-order functions like Haskell, it's simply useful to have a function which performs function application. For example, one place that ($) comes in handy is when applying each function in a list of functions to a single input value. Using ($) you can just write something like map ($5) [(+1), (^2), abs] which evaluates to [6,25,5]. -Brent

They definitely dropped the ball on introducing '$'. I think you just hit the seam between two of the authors, and it fell through the cracks.

2009/1/24 John Hartnup
But is that it's only purpose? To placate the LISP haters by removing parentheses?
On Jan 25, 2009, at 12:25 AM, David Morse wrote:
They definitely dropped the ball on introducing '$'. I think you just hit the seam between two of the authors, and it fell through the cracks.
Haskell isn't Cobol, but in comparison with the lambda calculus, it flows a bit better like a natural language. '$' helps with this. For example, in the line
mempty = en $ en []
...one clearly doesn't need to use $, parenthesizing (en []) has the same meaning. However, reading left-to-right, the $ coaxes one into dropping top-down into a new view of the line, partially abstracting out or forgetting what came before, without having to maintain a mental stack and brace oneself for the closing ). I've read books on numeracy and vision, that present the same conclusion: As our brain evolved new systems for seeing or counting, the old systems didn't get thrown out, they got buried by the new layers, but they're still wired in. Part of our reaction to a line of lisp that ends in seven )))))) is no different than a pigeon or a horse seeing the same number of objects; we're not sure. Then for us a new linguistic layer kicks in, "I can see two groups of three, that's even" and we rise above the animals, but our single conscious core got hijacked to sort this out. People take the ergonomics of cockpit design very seriously, to reduce the cognitive load on pilots in emergencies. On Apollo 13, they nearly blew it by flipping a switch the wrong way. I fly a lot, so I'm very grateful that the "purists" that gravitate to math and computer science aren't instead in ergonomic design. I actually love lisp, or more precisely Scheme. I came back to Haskell for strong typing and class abstractions; Haskell more directly supports making a theory about what one is coding. In order to use Scheme, I had to defang it of its parentheses. I didn't believe that any of the web proposals for this saw actual use, so I rolled my own preprocessor, using indentation to indicate outline structure, and using '|' roughly as Haskell uses '$'. There are other issues one inevitably faces, e.g. missing starts to outline levels, but I came to love '$' as Haskell uses it. Some people develop a point-free style in Haskell, e.g.
blah foo . blah . blah foo foo . blah
and different people write code that piles up uses of '$' e.g.
blah foo $ blah $ blah foo foo $ blah
With decent syntax coloring the second line can be given as light a touch as the first. Ultimately, '$' helps mitigate a left / right tension in Haskell that exists in all languages, and in algebra itself. In algebra, "f g" can mean either "f then g" or "g then f". It means "g then f" in any situation crippled by the ancestry of the function composition "f(g(x))", and it means "f then g" any time one has the free choice of easier ergonomics in a culture that reads left to right. Quick, ten times, work out out the permutation cycle product
(1 2 3) (2 3 4 5) (3 4 5 6) (4 5 6 2) (5 6 1 2) (1 2 3) (2 3 4 5) (3 4 5 6) (4 5 6 2) (5 6 1 2)
under each assumption for the order of operations. One wraps around through parentheses either way, but using the "f then g" convention, all other scanning is consistently left to right, not flitting back and forth like a deranged water bug. Now try composing a complex set of type signatures for Haskell functions. Do you feel like a deranged water bug? The arrows go the wrong way, don't they! You'd be playing a nice game of dominoes, canceling off neighbors and so forth, if the arrows went the other way. So Haskell doesn't have its left / right tension completely worked out, but I'd say '$' isn't part of the problem, it's part of the solution.

2009/1/24 John Hartnup
But is that it's only purpose? To placate the LISP haters by removing parentheses?
Also one important difference is that the standard application operator (space) associates to the left while $ associates to the right. It says how missing parenthesis are filled in. For example (a b c d e) stands for ((((a b) c) d) e) while (a $ b $ c $ d $ e) stands for (a (b (c (d e)))) Sometimes you need the former behavior sometimes the later. The $ is useful for example when an argument to an unary function is itself a function application. For example you can write filter (<4) $ map (+1) $ [100,99,1,2,3,4] In this case you can think of $ to be like a "unix pipe". Sincerely, jan.

On Sat, Jan 24, 2009 at 07:37:29PM +0000, John Hartnup wrote:
Hi.
I'm working through Real World Haskell, and although it's going well (I just finished the exercise to write a glob matcher without using a regex library, and I'm pleased as punch), I keep seeing the ($) operator, and I'm not sure I understand its use. If the book explains it, I've been unable to find it.
Empirically, it seems like: a $ b c d e f .. is equivalent to .. a (b c d e f)
But is that it's only purpose? To placate the LISP haters by removing parentheses?
(1 +) 2 does the same thing as (1 +) $ 2, and has the same type.
Am I missing something?
Thanks, John
I made some Examples for better understanding: -- creating an $ like function: f g x = (g x) -- some tests comparing $ with f: 5 == ($ 2) (+ 3) 5 == (`f` 2) (+ 3) 5 == (\x -> (($) x 2)) (+ 3) 5 == (\x -> (f x 2)) (+ 3) Regards
participants (7)
-
Brent Yorgey
-
Daniel Fischer
-
Dave Bayer
-
David Morse
-
Frank Schwidom
-
Jan Jakubuv
-
John Hartnup