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 returns how many words this string has. Run
> let countWords s = length $ words s
> countWords "a b c"
. 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
> let countWords s = length . words s
* 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:
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
> let countWords s = (length . words) s
> countWords "a b c"
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
* 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"
The same as:
> length $ words $ "1 2 3"