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)
() 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 () .
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With