Differentiate “application operator” and “function composition” in Haskell

I don’t know other guys, but for me, sometimes I am confused with $ (“application operator”) and . (“function composition”) in Haskell, so I want to write a small summary to differentiate them.

Check the type of these two operators:

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

For infix operator, $, its left operand should be a function whose type is a->b, the right operand should be the input parameter of this function: a, then get the result b. Check following example:

countWords :: String -> Int
countWords s = length $ words s

words returns a String list which is the input argument of length, then length returns how many words this string has. Run countWords in ghci:

> let countWords s = length $ words s
> countWords "a b c"
3

See . now; maybe another the type notation of . can give you a hand in comprehending it:

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

We can think the operands of . are both functions, and the return value is also a function. however, the three functions are not random, but have relationships with their parameters. Modify countWords and run it in ghci:

> let countWords s = length . words s

<interactive>:12:29: error:
    * Couldn't match expected type `a -> [a0]'
                  with actual type `[String]'
    * Possible cause: `words' is applied to too many arguments
      In the second argument of `(.)', namely `words s'
      In the expression: length . words s
      In an equation for `countWords': countWords s = length . words s
    * Relevant bindings include
        countWords :: String -> a -> Int (bound at <interactive>:12:5)

Woops! Error is generated. The reason is the space ” “, or function application has the highest precedence, so words s should be evaluated first:

:t words
words :: String -> [String]

The return value is [String], not a function, so it doesn’t satisfy the type of . who requires the two operands must be functions. Change the countWordsdefinition:

> let countWords s = (length . words) s
> countWords "a b c"
3

This time it works like a charm! For the same reason, the second operand of $ must be consistent with the input parameter of the first operand:

> let countWords = length $ words

<interactive>:18:18: error:
    * No instance for (Foldable ((->) String))
        arising from a use of `length'
    * In the expression: length $ words
      In an equation for `countWords': countWords = length $ words

It is time to warp it up: the operands of . is function, and we can use .to chain many functions to generate a final one which works as the left operand of $, feed it with one argument and produce the final result. Like this:

> length . words $ "1 2 3"
3

The same as:

> length $ words $ "1 2 3"
3

One thought on “Differentiate “application operator” and “function composition” in Haskell”

  1. Finally someone who understands my pain, I always mix them up. The example makes it clear and explanation is great, thanks 😀

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.