While I understand a little about currying in the mathematical sense, partially
applying an infix function was a new concept which I discovered after diving
into the book Learn You a Haskell for Great Good.
Given this function:
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)
The author uses it in a interesting way:
ghci> applyTwice (++ [0]) [1]
[1,0,0]
ghci> applyTwice ([0] ++) [1]
[0,0,1]
Here I can see clearly that the resulting function had different parameters
passed, which would not happen by normal means considering it is a curried
function (would it?). So, is there any special treatment on infix sectioning by
Haskell? Is it generic to all infix functions?
As a side note, this is my first week with Haskell and functional programming,
and I'm still reading the book.
Yes, you can partially apply an infix operator by specifying either its left or right operand, just leaving the other one blank (exactly in the two examples you wrote).
So, ([0] ++) is the same as (++) [0] or \x -> [0] ++ x (remember you can turn an infix operator into a standard function by means of parenthesis), while (++ [0]) equals to \x -> x ++ [0].
It is useful to know also the usage of backticks, ( `` ), that enable you to turn any standard function with two arguments in an infix operator:
Prelude> elem 2 [1,2,3]
True
Prelude> 2 `elem` [1,2,3] -- this is the same as before
True
Prelude> let f = (`elem` [1,2,3]) -- partial application, second operand
Prelude> f 1
True
Prelude> f 4
False
Prelude> let g = (1 `elem`) -- partial application, first operand
Prelude> g [1,2]
True
Prelude> g [2,3]
False
Yes, this is the section syntax at work.
Sections are written as ( op e ) or ( e op ), where op is a binary operator and e is an expression. Sections are a convenient syntax for partial application of binary operators.
The following identities hold:
(op e) = \ x -> x op e
(e op) = \ x -> e op x
All infix operators can be used in sections in Haskell - except for - due to strangeness with unary negation. This even includes non-infix functions converted to infix by use of backticks. You can even think of the formulation for making operators into normal functions as a double-sided section:
(x + y) -> (+ y) -> (+)
Sections are (mostly, with some rare corner cases) treated as simple lambdas. (/ 2) is the same as:
\x -> (x / 2)
and (2 /) is the same as \x -> (2 / x), for an example with a non-commutative operator.
There's nothing deeply interesting theoretically going on here. It's just syntactic sugar for partial application of infix operators. It makes code a little bit prettier, often. (There are counterexamples, of course.)
Related
Hutton's "Programming in Haskell", first edition, says that the concatenation operator ++ could be defined as:
(++ ys) = foldr (:) ys
This makes logical sense.
I had never seen an operator being defined by an equation on one of its sections (in this case (++ ys)), so I tried it myself:
(##) :: [a] -> [a] -> [a]
(## ys) = foldr (:) ys
However this doesn't compile, higlighting a syntax error in (## ys).
Has this never been a feature, or has it been removed at some point? If so, why?
I know I could write the above as:
xs ## ys = foldr (:) ys xs
But I find the point-free style more elegant.
This would result in some subtle inconsistencies. Although we tend to think of curried and flipped and uncurried functions as just different ways of writing the same thing, that is not quite true when it comes to the actual evaluation strategy. Consider
(#>) :: Integer -> Integer -> Integer
(#>) n = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
Indexing prime numbers is costly. If you write something like
map ((2^43) #>) [100 .. 150]
then the 243-th prime number needs to be computed only once. By contrast, if I define
(<#) :: Integer -> Integer -> Integer
(<#) = flip foo
then writing map (<# (2^43)) [100 .. 150] would compute the prime number over and over again, because Haskell doesn't support partially applying functions on the second argument.
With the flip foo definition this isn't too surprising, but if I could have defined the flipped form directly as
(<#n) = let p = {- the `n`-th prime number -} `mod` 74
in (p+)
then one could reasonably expect that map (<# (2^43)) does share the prime computation, but to support that Haskell's partial evaluation semantics would need to track more information than they currently do, and if we want this to work reliably then it would probably incur some other disadvantages.
I think there's a simpler explanation to do with how complex already are the allowed syntactic forms on lhs of an = binding.
Please always post the error message you're getting, don't just say "higlighting a syntax error". The message might not mean a lot to you, but in this case it gives a strong hint:
(## ys) = ...
===> error: Parse error in pattern: ##ys
(xs ##) = ...
===> error: Expression syntax in pattern: xs ##
"in pattern" aha! That is, the lhs is potentially a syntactic pattern. Furthermore there might not be a signature decl for whatever you're introducing; even if there is, the compiler has to check your equation against the signature, so it can't assume anything about the arity of what you're introducing. Consider these valid equations
z = 42 -- z counts as a pattern
Just z = {- long and complex expr returning a Maybe, binds z at module-wide scope -}
(Just z) = {- same same, binds z at module-wide scope -}
foo x = ... -- foo gets module-wide scope but not x
(foo x) = ... -- same
bar x y = ... -- bar gets module-wide scope but not x, y
(bar x) y = ... -- same
(x ## y) z = ... -- accepted, introduces triadic operator ##
x ## y z = -- rejected error: Parse error in pattern: y
(x ##) y = -- rejected error: Expression syntax in pattern: x ##
(## y) z = -- rejected error: Parse error in pattern: ##y
The Language Report (section 4.4.3 Function and Pattern Bindings) has
decl -> (funlhs | pat) rhs
funlhs -> var apat { apat }
| pat varop pat
| ( funlhs ) apat { apat }
So the lhs is not a place where expression syntax (incl operator sections) can appear. See also the ugly detail at the end of section 4.4.3.1 to do with using lhs operator syntax in combo with a infix data constructor ugh!
The last sentence here also confirms you can't use operator sections on lhs.
In Programming in Haskell by Hutton
In general, if # is an operator, then expressions of the form (#), (x #), and (# y) for arguments x and
y are called sections, whose meaning as functions can be
formalised using lambda expressions as follows:
(#) = \x -> (\y -> x # y)
(x #) = \y -> x # y
(# y) = \x -> x # y
What are the difference and relation between "section" and "currying"?
Is a section the result of applying the currying operation to a multi-argument function?
Thanks.
A section is just special syntax for applying an infix operator to a single argument. (# y) is the more useful of the two, as (x #) is equivalent to (#) x (which is just applying the infix operator as a function to a single argument in the usual fashion).
curry f x y = f (x,y). uncurry g (x,y) = g x y.
(+ 3) 4 = (+) 4 3 = 4 + 3. (4 +) 3 = (+) 4 3 = 4 + 3.
A section is a result of partial application of a curried function: (+ 3) = flip (+) 3, (4 +) = (+) 4.
A curried function (like g or (+)) expects its arguments one at a time. An uncurried function (like f) expects its arguments in a tuple.
To partially apply an uncurried function we have first to turn it into a curried function, with curry. To partially apply a curried function we don't need to do anything, just apply it to an argument.
curry :: ((a, b) -> c ) -> ( a -> (b -> c))
uncurry :: (a -> (b -> c)) -> ((a, b) -> c )
x :: a
g :: a -> (b -> c)
--------------------
g x :: b -> c
x :: a
f :: (a, b) -> c
---------------------------
curry f :: a -> (b -> c)
curry f x :: b -> c
Left sections and right sections are syntactical devices for partially applying an infix operator to a single argument (see also chepner's answer). For the sake of accuracy, we should note that currying is not the same thing as partial application:
Currying is converting a function that takes N arguments into a function that takes a single argument and returns a function that takes N-1 arguments.
Partial application is making a function that takes N-1 arguments out of a function that takes N arguments by supplying one of the arguments.
In Haskell, it happens that everything is curried; all functions take just one argument (even uncurried functions in Haskell take a tuple, which is, strictly speaking, a single argument -- you might want to play with the curry and uncurry functions to see how that works). Still, we very often think informally of functions that return functions as functions of multiple arguments. From that vantage point, a nice consequence of currying by default is that partial application of a function to its first argument becomes trivial: while, for instance, elem takes a value and a container and tests if the value is an element of the contaier, elem "apple" takes a container (of strings) and tests if "apple" is an element of it.
As for operators, when we write, for instance...
5 / 2
... we are applying the operator / to the arguments 5 and 2. The operator can also be used in prefix form, rather than infix:
(/) 5 2
In prefix form, the operator can be partially applied in the usual way:
(/) 5
That, however, arguably looks a little awkward -- after all, 5 here is the numerator, and not the denominator. I'd say left section syntax is easier on the eye in this case:
(5 /)
Furthermore, partial application to the second argument is not quite as straightforward to write, requiring a lambda, or flip. In the case of operators, a right section can help with that:
(/ 2)
Note that sections also work with functions made into operators through backtick syntax, so this...
(`elem` ["apple", "grape", "orange"])
... takes a string and tests whether it can be found in ["apple", "grape", "orange"].
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.
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) doesn't have an input, and therefore cannot be used with the . operator.
show can take an Int and return a String.
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
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 .
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)
($) 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"
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.
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.
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.
... 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
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]
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 ()!
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 )
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 .
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.
I'm currently getting started with Haskell (reading Learn Yourself a Haskell),
and came across lines akin to the following:
map (++"!") ["a", "b"] -- ["a!", "b!"]
map ("!"++) ["a", "b"] -- ["!a", "!b"]
Why is this possible, or how does it work? I can't manage to do the same with other non-commutative operations, like division:
map (3/) [1..3] -- [3.0,1.5,1.0]
map ((/)3) [1..3] -- [3.0,1.5,1.0]
map (3(/)) [1..3] -- error
I feel like I'm missing something here, but the implementation of map doesn't give me any hints.
This code is not valid:
map (3(/)) [1..3]
(/) is prefix function but you use it as infix. Compiler see it as you try to function 3 (a function without arguments), add (/) as an argument.
/ is infix function. So, you can do next:
map ( / 3) [1..3] -- [0.3333333333333333,0.6666666666666666,1.0]
map (3 / ) [1..3] -- [3.0,1.5,1.0]
This is not at all related to map; map’s argument can just be any function.
To understand the functions that you have passed, look at this GHCi session:
Prelude> :t (++"!")
(++"!") :: [Char] -> [Char]
Prelude> (++"!") "Hello"
"Hello!"
Prelude> ("!"++) "Hello"
"!Hello"
Prelude> :t ("!"++)
("!"++) :: [Char] -> [Char]
What is happening here is the syntactic idea of operation sections (Haskell report, Sec. 3.4), which can be read as
(x •) == (\y. x • y)
(• x) == (\y. y • x)
where • can be any operation like ++, * or even funny self-defined operators like ^_^.
If a function is declared in brackets: (++) :: [a] -> [a] -> [a], it can be used with and without them. If used without brackets, they must appear between the arguments: "!" ++ "?", but with the brackets they are just like normal functions: (++) "!" "?".
Haskell permits "partial application" of functions, so ("!"++) is the same as (++) "!" or \x -> (++) "!" x, and (++"?") is the same as \x -> (++) x "?". ("Partial application" is in quotes, because the functions in Haskell always have just one argument, so application is no longer "partial"; in other languages (++) would be viewed as a function of two arguments, so when only one argument is applied, the function is deemed partially applied - in this sense it may be useful to view ("!"++) as a partially applied (++))
Your second example is a valid way of using (/), but if you use (/), it really is not a infix function anymore, so you get a error attempting to specify the first argument to (/) before the function name: 3(/). It still works if you remove the brackets: (3 /) is the same as ((/) 3) or (\x -> (/) 3 x) or (\x -> 3 / x)
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.
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) doesn't have an input, and therefore cannot be used with the . operator.
show can take an Int and return a String.
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
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 .
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)
($) 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"
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.
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.
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.
... 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
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]
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 ()!
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 )
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 .
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.