0

Replacing the parentheses in this function:

isInteger x = x == fromInteger (round x)

with a dollar sign operator:

isInteger x = x == fromInteger $ round x

raises an error.

What are the limitations of using the $ operator?

Trajanson
  • 441
  • 3
  • 11
  • The best SO question doesn't handle this issue: http://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign – Trajanson May 08 '16 at 20:34
  • It's just a low-precedence infix operator. You get an error about this for the same reason `3 * 5 + 7` means `(3*5) + 7` rather than `3 * (5+7)`. – Daniel Wagner May 08 '16 at 20:44
  • @DanielWagner can you please define an 'infix operator' as you understand the term? – Trajanson May 08 '16 at 20:48
  • 2
    [The Report](https://www.haskell.org/onlinereport/haskell2010/haskellch2.html#x7-180002.4) is the canonical reference. Any sequence of symbols is an infix operator. – Daniel Wagner May 08 '16 at 21:03

2 Answers2

6

$ has extremely low precedence, lower than ==, lower than everything. Your attempt is parsed as

isInteger x = (x == fromInteger) $ (round x)

that is, it attempts to apply a Bool as a function. You could write

isInteger x = x == (fromInteger $ round x)

but that doesn't really save any parentheses; it just shifts them.


If you really want to get rid of the parentheses (or at least, really move them aside), you can take advantage of the fact that (-> r) is an applicative functor, which in brief means that f <*> g == \x -> f x (g x). Replacing f with (==) and g with fromInteger . round, you get

isInteger = (==) <*> fromInteger . round

because

x == fromInteger (round x) -> (==) x (fromInteger (round x))
                           -> (==) x ((fromInteger . round) x)
                              ----    ---------------------
                               f   x (          g           x)
chepner
  • 497,756
  • 71
  • 530
  • 681
  • 1
    This is a good clarification of Learn You a Haskell's explanation: "you can imagine a $ being sort of the equivalent of writing an opening parentheses and then writing a closing one on the far right side of the expression." – Trajanson May 08 '16 at 21:00
  • 5
    While we're quoting LYAH, I should also mention "[functions] are rarely used with the applicative style outside of code golf". It's clever, concise, and barely readable :) – chepner May 08 '16 at 21:14
  • 1
    @chepner It's sort of readable if you think of it as the `Reader` monad. – PyRulez May 09 '16 at 01:35
1

This is the beginning of the accepted answer in the question you linked in the comment:

The $ operator is for avoiding parentheses. Anything appearing after it will take precedence over anything that comes before.

Taking this into account, isInteger x = x == fromInteger $ round x becomes isInteger x = (x == fromInteger) (round x), so you're taking the result of x == fromInteger (which is of type Bool) and applying it to round x. This clearly doesn't make sense.

Kapol
  • 6,383
  • 3
  • 21
  • 46