Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why/when can't $ be used instead of parentheses in Haskell?

Tags:

haskell

I have the impression that I can use $ ... to represent (...) as long as there is nothing to the right of ....

However, when I try to re-write the following

dist' x y = abs  <$> ( (-) <$> x <*> y)

as

dist x y = abs  <$> $ (-) <$> x <*> y

I get an error:

 error: …
    parse error on input ‘$’
    Perhaps you intended to use TemplateHaskell
  |
Compilation failed.

I can live with writing the parenthesis, but I am just curious. Why (or when) does the $ not work in replacing ().

(This is with GHC 8.2.2)

like image 733
thor Avatar asked Apr 23 '18 23:04

thor


People also ask

What does () mean in Haskell?

() is very often used as the result of something that has no interesting result. For example, an IO action that is supposed to perform some I/O and terminate without producing a result will typically have type IO () .

What do parentheses mean in Haskell?

If you use parentheses it's only to delimit individual arguments (if they are expressions); and commas are used to separate tuple elements. So if you see something like this: f (a, b, c) you interpret it as a call to (application of) a function f to just one argument -- a tuple of three elements.

What does square brackets mean in Haskell?

In Haskell, a list is a data structure that can store multiple items of the same type. For example, a list of integers or a list of characters. A string in Haskell is considered to be a list of characters. Square brackets are used to define a list.

What is dollar in Haskell?

The dollar sign, $ , is a controversial little Haskell operator. Semantically, it doesn't mean much, and its type signature doesn't give you a hint of why it should be used as often as it is. It is best understood not via its type but via its precedence.


1 Answers

Although it is in practice indeed used primarily for this purpose, the $ operator is not in any fundamental way syntactically linked to parenthisation – it's just another infix operator (i.e. 2-argument function written in the middle between arguments), like + or * or <$>. What the operator does is take a function on its left side and a value that the function should be applied to on the right. So, for instance sqrt (1 - x^2) can be written sqrt $ 1 - x^2, because sqrt is just a function and instead of flat out applying the function to its argument you can also use the $ to do the same thing, benefiting from the low infixr 0 $.

The function may also be a composition or partial application of other stuff, as in

(sum . map (^2)) (0 : xs)   ≡   sum . map (^2) $ 0 : xs

But abs <$> ((-) <$> x <*> y) is not of this form: it is already an infix expression.

We can however exploit the fact that Haskell allows partial application also of infix operators, because that gives you a simple function form. You need an operator section:

abs <$> ((-) <$> x <*> y)   ≡   (abs <$>) ((-) <$> x <*> y)

and this is now of simple function-application form, so you can make it

(abs <$>) $ (-) <$> x <*> y

Of course that somewhat defeats the point, because the operator section has introduced another pair of parentheses, so in this case the original way of writing the expression probably remains the best. Fortunately though, <$> also comes in a plain-function form, namely

fmap abs $ (-) <$> x <*> y

Another option would be to rewrite the <*> subexpression: f <$> a <*> b is the same as liftA2 f a b, which as a plain function binds tighter than the infix <$> anyway. So

abs <$> ((-) <$> x <*> y)   ≡   abs <$> liftA2 (-) x y

Or alternatively, remove the outer fmap entirely: if you first define

numDist :: Num a => a -> a -> a
numDist a b = abs $ a - b

then you can just write

dist x y = numDist <$> x <*> y

...or

dist = liftA2 numDist
like image 182
leftaroundabout Avatar answered Oct 12 '22 10:10

leftaroundabout