What does $ mean/do in Haskell?
Asked Answered
H

2

68

When you are writing slightly more complex functions I notice that $ is used a lot but I don't have a clue what it does?

Hypoderm answered 22/10, 2013 at 14:51 Comment(1)
It's the "apply" operator. This blog does an alright job getting the basic of it covered: snakelemma.blogspot.com/2009/12/dollar-operator-in-haskell.htmlLevey
C
80

$ is infix "application". It's defined as

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

-- or 
($) f x = f x
-- or
($) = id

It's useful for avoiding extra parentheses: f (g x) == f $ g x.

A particularly useful location for it is for a "trailing lambda body" like

forM_ [1..10] $ \i -> do
  l <- readLine
  replicateM_ i $ print l

compared to

forM_ [1..10] (\i -> do
  l <- readLine
  replicateM_ i (print l)
)

Or, trickily, it shows up sectioned sometimes when expressing "apply this argument to whatever function"

applyArg :: a -> (a -> b) -> b
applyArg x = ($ x)

>>> map ($ 10) [(+1), (+2), (+3)]
[11, 12, 13]
Cominform answered 22/10, 2013 at 14:56 Comment(7)
Yep. It's also written f . g . h $ x sometimes, which could also be (f . g . h) x.Cominform
Technical note: AFAIK, the definition of $ is a bit of a lie at present. GHC actually treats it as syntax so that the runST $ do idiom works (except in things like sections where it really is a function). It should be just a function, but higher rank types are a problem.Mongrelize
Agreed—source from Simon Peyton Jones hereCominform
<$> is just infix fmap. It doesn't do anything special as far as I know.Cominform
It might be worth pointing out, along with the operators's signature, that its PRECEDENCE is 0. So, everything binds more tightly than $.Xerarch
What if I write (10 $) in your last example. It doesn't produce any output.Cordie
@johnbakers (a->b)->a->b is same as (a->b)->(a->b) because -> is right associative.Beacham
R
32

I like to think of the $ sign as a replacement for parenthesis.

For example, the following expression:

take 1 $ filter even [1..10] 
-- = [2]

What happens if we don't put the $? Then we would get

take 1 filter even [1..10]

and the compiler would now complain, because it would think we're trying to apply 4 arguments to the take function, with the arguments being 1 :: Int, filter :: (a -> Bool) -> [a] -> [a], even :: Integral a => a -> Bool, [1..10] :: [Int].

This is obviously incorrect. So what can we do instead? Well, we could put parenthesis around our expression:

(take 1) (filter even [1..10])

This would now reduce to:

(take 1) ([2,4,6,8,10])

which then becomes:

take 1 [2,4,6,8,10]

But we don't always want to be writing parenthesis, especially when functions start getting nested in each other. An alternative is to place the $ sign between where the pair of parenthesis would go, which in this case would be:

take 1 $ filter even [1..10]

Rhapsodist answered 14/5, 2016 at 15:25 Comment(2)
how does the compiler infer where the end of the parentheses goes?Regenerative
When it finds the next $ symbol otherwise the end of the line.Clement

© 2022 - 2024 — McMap. All rights reserved.