3
Prelude> p a b c=1
Prelude> p $ 2 $ 2 $ 5
tons of error......
Prelude> ($$)=($)
Prelude> p $$ 2 $$ 2 $$ 5
1
Prelude>p $$ [2..3] $$ 4 $$ 5
1
Prelude>p $$ [1]++[2..3] $$ 4 $$ 5 
tons of error......
Prelude>p $$ [1]++[2..3] $$ [1]++[2..3] $$ 5
of course, tons of error......

Question 1: Why ($) not works on "p $ 2 $ 2 $ 5"?

Question 2: Why ($$) works on "p $$ 2 $$ 2 $$ 5"?

Question 3: Why ($$) not works on "p $$ [1]++[2..3] $$ 4 $$ 5"?

Question 4: Is there a more elegant way to write "p $$ [1]++[2..3] $$ [1]++[2..3] $$ 5" correctly?

MaxC
  • 63
  • 6
  • You might want to read up on what `$` does. The purpose of a `$` is to help reduce the number of parentheses `()` in your expressions. Here's its type signature: `($) :: (a -> b) -> a -> b`. In other words, all it does is take a function and its *single* argument, and applies the function. Really boring. Terrifically boring. Does absolutely nothing useful (semantically). – Mateen Ulhaq Jun 01 '18 at 05:19
  • Possible duplicate of [What is the difference between . (dot) and $ (dollar sign)?](https://stackoverflow.com/questions/940382/what-is-the-difference-between-dot-and-dollar-sign) – Mateen Ulhaq Jun 01 '18 at 05:21
  • Hi, Mateen. Before I ask this question, I have read that question answer already. And I edited my question more accurately, thanks for your help. – MaxC Jun 01 '18 at 05:34
  • I believe it's because `($)` is a function with *high precedence*, whereas `$` is an infix operator but with *low precedence*. – Mateen Ulhaq Jun 01 '18 at 06:13

2 Answers2

5

The answers lie in operator precedence due to their fixity specifications.

($) has a precedence of 0 and associates to the right as can be seen by

Prelude> :i ($)
...                                                                                                                                                                                 
infixr 0 $   

If you want your custom operator to have the precedence and associativity that you're suggesting you will need to add the fixity declaration to your code:

infixl 0 $$
Daniel Wagner
  • 145,880
  • 9
  • 220
  • 380
pikapika
  • 376
  • 1
  • 7
4

The purpose of a $ is to help reduce the number of parentheses () in your expressions. Here's its type signature:

($) :: (a -> b) -> a -> b

In other words, all it does is take a function and its single argument, and applies the function. Really boring. Terrifically boring. That is to say:

($) f x = f x    , or more simply,
($) f = f        , or more simply,
($) = id

The only thing which makes ($) worthwhile is that it has a different precedence than a regular function like id. That is, ($) has a very low precedence; in contrast, regular functions such as id have a very high precedence in application.

When acting as an infix operator, $ is right associative. That's another useful property.


Question 1: Why ($) not works on "p $ 2 $ 2 $ 5"?

Let's get rid of some $ signs. The following are all equivalent:

  p $ 2 $ 2 $ 5
= p (2 $ 2 $ 5)
= p (2 (2 $ 5))
= p (2 (2 5))

I suppose you can figure out why an expression like (2 5) doesn't make any sense.


Question 2: Why ($$) works on "p $$ 2 $$ 2 $$ 5"?

When you define a new function such as ($$), it is given left assosciativity (and also highest precedence) by default. Then:

  p $$ 2 $$ 2 $$ 5
= (p 2) $$ 2 $$ 5
= ((p 2) 2) $$ 5
= ((p 2) 2) 5

This is of course plain old partial application.


Question 3: Why ($$) not works on "p $$ [1]++[2..3] $$ 4 $$ 5"?

  p $$ [1] ++ [2..3] $$ 4 $$ 5
= (((p $$ [1]) ++ [2..3]) $$ 4) $$ 5
= (((p [1]) ++ [2..3]) 4) 5

Question 4: Is there a more elegant way to write "p $$ [1]++[2..3] $$ [1]++[2..3] $$ 5" correctly?

Without the wacky $$, I suppose. :)

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
  • 2
    A couple parts of this are a bit inaccurate: Low precedence does not mean that operations on the right get grouped together first. That would be right associativity. Precedence is a number that tells you which operations get done before which other operations. Also, `($$)` is both a function and an infix operator (just like `($)` is). When you define an operator, [it defaults to the highest precedence and left associativity](https://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-240003.2). You tell Haskell to use a different precedence/associativity with `infixr` or `infixl`. – David Young Jun 01 '18 at 07:23
  • Additionally, there are some uses for `($)` other than removing parentheses. Consider something like ``map ($ 5) [(+1), (*10), (`mod` 2)]`` or ``zipWith ($) [(+1), (*10), (`mod` 2)] [1..]``. – David Young Jun 01 '18 at 07:27
  • @DavidYoung Thanks, I've made some adjustments. – Mateen Ulhaq Jun 01 '18 at 08:10