What is the difference between . (dot) and $ (dollar sign)?
Asked Answered
E

14

804

What is the difference between the dot (.) and the dollar sign ($)?

As I understand it, they are both syntactic sugar for not needing to use parentheses.

Elagabalus answered 2/6, 2009 at 16:6 Comment(0)
I
1364

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

For example, let's say you've got a line that reads:

putStrLn (show (1 + 1))

If you want to get rid of those parentheses, any of the following lines would also do the same thing:

putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1

The primary purpose of the . operator is not to avoid parentheses, but to chain functions. It lets you tie the output of whatever appears on the right to the input of whatever appears on the left. This usually also results in fewer parentheses, but works differently.

Going back to the same example:

putStrLn (show (1 + 1))
  1. (1 + 1) doesn't have an input, and therefore cannot be used with the . operator.
  2. show can take an Int and return a String.
  3. putStrLn can take a String and return an IO ().

You can chain show to putStrLn like this:

(putStrLn . show) (1 + 1)

If that's too many parentheses for your liking, get rid of them with the $ operator:

putStrLn . show $ 1 + 1
Indigested answered 17/8, 2009 at 22:1 Comment(13)
Actually, since + is a function too, couldn't you make it prefixed then compose it in as well, like ` putStrLn . show . (+) 1 1 ` Not that it's any clearer, but I mean... you could, right?Doornail
@Doornail In this example, something like putStrLn . show . (+1) $ 1 would be equivalent. You are correct in that most (all?) infix operators are functions.Indigested
After seeing putStrLn $ show $ 1 + 1, I honestly think, $ must be replaced with a light-weight character. I can't think of any right now , because they're all used up, but some character will emerge.Korrie
@Nawaz Correct, you would have to do something like (putStrLn . show . (+1)) 1Poole
I wonder why nobody ever mentions uses like map ($3). I mean, I mostly use $ to avoid parentheses as well, but it's not like that's all they're there for.Different
Be very careful with your use of $, though. It tends to continue the parenthesis to the end of the line, or end of the parentheses it is inside. Caused me many strange results when I was learning the language.Pyonephritis
@Different what is that map statement supposed to do?Reddick
map ($3) is a function of type Num a => [(a->b)] -> [b]. It takes a list of functions taking a number, applies 3 to all of them and collects the results.Different
@Cubic, thank you so much, at first I didn't grok what you meant but GHCI's type system helped me! For your edification, my example; ---code-- let try :: [Integer -> b] -> [b] ; try = map ($3) ; let adda :: Integer -> Integer ; adda x = 7 + x; let suba :: Integer -> Integer ; suba x = x - 7; -- now doing it: --; try [adda, suba] ; -- RESULT = [10,-4] ///I apologize we can't format comments as codeUltimogeniture
You have to be careful when using $ with other operators. "x + f (y +z)" is not the same as "x + f $ y + z" because the latter actually means "(x+f) (y+z)" (i.e. the sum of x and f is treated as a function).Evelinevelina
@AnneTheAgile: If you want a concise example: map ($3) [(\x->x+7),(\x->x-7)]. I tend to read $ as apply to in my head, so you apply the number 3 to two number-transforming functions in a list using map.Perceptible
@Doornail No, you could NOT. (+) is a "2 argument function", so your example would not work. You could however do it using composition of function composition (so called "tits operator"): putStrLn ((.).(.)) show ((.).(.)) (+) $ 1 1. I usually define (.:) = (.).(.) and then (putStrLn . show) .: (+) $ 1 1 works fine :)Kilgore
@WojciechDanilo, ahahahah, tits operator! It will stick in my mind!Tanyatanzania
F
216

They have different types and different definitions:

infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)

infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x

($) is intended to replace normal function application but at a different precedence to help avoid parentheses. (.) is for composing two functions together to make a new function.

In some cases they are interchangeable, but this is not true in general. The typical example where they are is:

f $ g $ h $ x

==>

f . g . h $ x

In other words in a chain of $s, all but the final one can be replaced by .

Friedlander answered 2/6, 2009 at 16:14 Comment(2)
What if x was a function? Can you then use . as the final one?Lamb
@Lamb if you're actually applying x in this context, then yes - but then the "final" one would be applying to something other than x. If you're not applying x, then it's no different to x being a value.Friedlander
B
137

Also note that ($) is the identity function specialised to function types. The identity function looks like this:

id :: a -> a
id x = x

While ($) looks like this:

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

Note that I've intentionally added extra parentheses in the type signature.

Uses of ($) can usually be eliminated by adding parenthesis (unless the operator is used in a section). E.g.: f $ g x becomes f (g x).

Uses of (.) are often slightly harder to replace; they usually need a lambda or the introduction of an explicit function parameter. For example:

f = g . h

becomes

f x = (g . h) x

becomes

f x = g (h x)
Betroth answered 2/6, 2009 at 16:32 Comment(3)
"Note that I've intentionally added extra parentheses in the type signature." I'm confused... why'd you do this?Rachitis
@MateenUlhaq The type of ($) is (a -> b) -> a -> b, which is the same as (a -> b) -> (a -> b), but the extra parentheses do here add some clarity.Mann
Oh, I suppose. I was thinking of it as a function of two arguments... but because of currying, it's exactly equivalent to a function that returns a function.Rachitis
N
84

($) allows functions to be chained together without adding parentheses to control evaluation order:

Prelude> head (tail "asdf")
's'

Prelude> head $ tail "asdf"
's'

The compose operator (.) creates a new function without specifying the arguments:

Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'

Prelude> let second = head . tail
Prelude> second "asdf"
's'

The example above is arguably illustrative, but doesn't really show the convenience of using composition. Here's another analogy:

Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"

If we only use third once, we can avoid naming it by using a lambda:

Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"

Finally, composition lets us avoid the lambda:

Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"
Nuri answered 7/1, 2010 at 1:43 Comment(1)
If the stackoverflow had a combination function, I would prefer the answer combining the previous two explanations with the example in this answer.Demesne
O
62

The short and sweet version:

  • ($) calls the function which is its left-hand argument on the value which is its right-hand argument.
  • (.) composes the function which is its left-hand argument on the function which is its right-hand argument.
Ophiolatry answered 10/6, 2009 at 20:11 Comment(0)
B
37

One application that is useful and took me some time to figure out from the very short description at Learn You a Haskell: Since

f $ x = f x

and parenthesizing the right hand side of an expression containing an infix operator converts it to a prefix function, one can write ($ 3) (4 +) analogous to (++ ", world") "hello".

Why would anyone do this? For lists of functions, for example. Both:

map (++ ", world") ["hello", "goodbye"]
map ($ 3) [(4 +), (3 *)]

are shorter than

map (\x -> x ++ ", world") ["hello", "goodbye"]
map (\f -> f 3) [(4 +), (3 *)]

Obviously, the latter variants would be more readable for most people.

Bjorn answered 31/1, 2010 at 12:12 Comment(3)
btw, I'd advise against using $3 without the space. If Template Haskell is enabled, this will be parsed as a splice, whereas $ 3 always means what you said. In general there seems to be a trend in Haskell to "stealing" bits of syntax by insisting that certain operators have spaces around them to be treated as such.Friedlander
Took me a while to figure out how the parentheses were working: en.wikibooks.org/wiki/Haskell/…Extractive
Usually on a great question like this, we see one really great answer. However, we have multiple fantastic answers, and each one elucidates the point further and provides yet another aspect that helps in the understanding. Love it!Sunburn
D
33

Haskell: difference between . (dot) and $ (dollar sign)

What is the difference between the dot (.) and the dollar sign ($)?. As I understand it, they are both syntactic sugar for not needing to use parentheses.

They are not syntactic sugar for not needing to use parentheses - they are functions, - infixed, thus we may call them operators.

Compose, (.), and when to use it.

(.) is the compose function. So

result = (f . g) x

is the same as building a function that passes the result of its argument passed to g on to f.

h = \x -> f (g x)
result = h x

Use (.) when you don't have the arguments available to pass to the functions you wish to compose.

Right associative apply, ($), and when to use it

($) is a right-associative apply function with low binding precedence. So it merely calculates the things to the right of it first. Thus,

result = f $ g x

is the same as this, procedurally (which matters since Haskell is evaluated lazily, it will begin to evaluate f first):

h = f
g_x = g x
result = h g_x

or more concisely:

result = f (g x)

Use ($) when you have all the variables to evaluate before you apply the preceding function to the result.

We can see this by reading the source for each function.

Read the Source

Here's the source for (.):

-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.)    :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)

And here's the source for ($):

-- | Application operator.  This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- >     f $ g $ h x  =  f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($)                     :: (a -> b) -> a -> b
f $ x                   =  f x

Conclusion

Use composition when you do not need to immediately evaluate the function. Maybe you want to pass the function that results from composition to another function.

Use application when you are supplying all arguments for full evaluation.

So for our example, it would be semantically preferable to do

f $ g x

when we have x (or rather, g's arguments), and do:

f . g

when we don't.

Degust answered 9/11, 2017 at 23:12 Comment(1)
Amongst all the great answers, I think this one perhaps should be read "first" - it provides the most accurate and best-understood explanation. And yet, the other answers still provide further information.Sunburn
E
13

... or you could avoid the . and $ constructions by using pipelining:

third xs = xs |> tail |> tail |> head

That's after you've added in the helper function:

(|>) x y = y x
Exquisite answered 4/12, 2012 at 10:24 Comment(4)
Yes, |> is the F# pipeline operator.Exquisite
One thing to note here, is that Haskell's $ operator actually works more like F#'s <| than it does |>, typically in haskell you'd write the above function like this: third xs = head $ tail $ tail $ xs or perhaps even like third = head . tail . tail, which in F#-style syntax would be something like this: let third = List.head << List.tail << List.tailAirline
Why add a helper function to make Haskell look like F#? -1Torquemada
The flipped $ is already available, and it's called & hackage.haskell.org/package/base-4.8.0.0/docs/…Euchromosome
G
13

My rule is simple (I'm beginner too):

  • do not use . if you want to pass the parameter (call the function), and
  • do not use $ if there is no parameter yet (compose a function)

That is

show $ head [1, 2]

but never:

show . head [1, 2]
Glanville answered 20/8, 2013 at 15:53 Comment(1)
Good heuristic, but could use more examplesBicyclic
M
12

A great way to learn more about anything (any function) is to remember that everything is a function! That general mantra helps, but in specific cases like operators, it helps to remember this little trick:

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

and

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

Just remember to use :t liberally, and wrap your operators in ()!

Michelinemichell answered 15/4, 2015 at 6:10 Comment(0)
S
2

The most important part about $ is that it has the lowest operator precedence.

If you type info you'll see this:

λ> :info ($)
($) :: (a -> b) -> a -> b
    -- Defined in ‘GHC.Base’
infixr 0 $

This tells us it is an infix operator with right-associativity that has the lowest possible precedence. Normal function application is left-associative and has highest precedence (10). So $ is something of the opposite.

So then we use it where normal function application or using () doesn't work.

So, for example, this works:

λ> head . sort $ "example"
λ> e

but this does not:

λ> head . sort "example"

because . has lower precedence than sort and the type of (sort "example") is [Char]

λ> :type (sort "example")
(sort "example") :: [Char]

But . expects two functions and there isn't a nice short way to do this because of the order of operations of sort and .

Sanson answered 8/6, 2020 at 18:5 Comment(1)
This answers exactly what I confused about before, that is why we need to use the ($) operator in a function composition's applications. Very nice, if I had thoroughly browsed this page, I wouldn't write my own answer, I think my answer is so far less concise and error-prone than yours. sadge :)Seigneur
C
1

I think a short example of where you would use . and not $ would help clarify things.

double x = x * 2
triple x = x * 3
times6 = double . triple

:i times6
times6 :: Num c => c -> c

Note that times6 is a function that is created from function composition.

Caprine answered 15/10, 2016 at 23:26 Comment(1)
Yeah, we shall actually deem a function composition as a single function instead of the process of getting the output of one function as the another function's input, but instead treat it as a "single" function taking one input and returning one output.Seigneur
R
1

All the other answers are pretty good. But there’s an important usability detail about how ghc treats $, that the ghc type checker allows for instatiarion with higher rank/ quantified types. If you look at the type of $ id for example you’ll find it’s gonna take a function whose argument is itself a polymorphic function. Little things like that aren’t given the same flexibility with an equivalent upset operator. (This actually makes me wonder if $! deserves the same treatment or not )

Rowdy answered 9/8, 2018 at 2:59 Comment(0)
S
1

This post explains why the (.) and ($) infix functions(operators) are different.

The most confusing part is where we use the dollar ($) operator in a function composition applied to an input.

The type and definition of the (.) operator:

(.) :: (b -> c) -> (a -> c) -> a -> c
f . g = \x -> f (g x)
-- It should really be defined as follows to make it clear of the syntax,
-- but looks weird since most functions aren't defined like this.
(f . g) x = f (g x)

Why don't we just simply use it with syntax like follows but need the ($) operator before the function that's applied to its input or just before the input?

-- The part "(map (*5))" enclosed with parentheses,
-- is to explictly indicate it's partially applied as a function that takes a list as the argument. 
replicate 3 . reverse . (map (*5)) [1..2]

But must be like follows?

replicate 3 . reverse $ (map (*5)) [1..2]
-- Or 
replicate 3 . reverse . (map (*5)) $ [1..2]

Suppose we have a function that takes three arguments, named "sumThreeNums" as

sumThreeNums :: Num a => a -> a -> a -> a
sumThreeNums n1 n2 n3 = n1 + n2 + n3

It takes three arguments as same as what the dot (.) operator which is defined for function composition does.

If used as an infix function(operator), we cannot give the third argument (4) as follows as the compiler will return an error about the syntax:

3 `sumThreeNums` 2 4

Instead, we need to enclose it as a function by partial application that takes the last one of arguments:

(3 `sumThreeNums` 2) 4

This is where the ($) operator comes in play, we can write the above expression as:

3 `sumThreeNums` 2 $ 4

Despite the fact that the ($) operator is used to add parentheses for the argument on the right, and make the expression to be right-associative, but it's defined with a fairly low precedence, which is lower than the (.) operator, this means we are actually adding "parentheses" for the argument on the left of the ($) operator that separates the left from the right and make the left take precedence because (.) has higher precedence than ($) in an expression, making the above usage possoble.

To sum it up, this is why we wrote a function composition applied to an input looks like

(replicate 3 . reverse) (map (*5) [1..2])
-- Or
(replicate 3 . reverse . map (*5)) [1..2]
-- Become as:
replicate 3 . reverse $ map (*5) [1..2]
-- Or 
replicate 3 . reverse . map (*5) $ [1..2]
Seigneur answered 25/11, 2023 at 16:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.