When you see type of .
you will notice that it expects both of its operands to be functions (of suitable types so that they can be composed)
Prelude> :i (.)
(.) :: (b -> c) -> (a -> b) -> a -> c -- Defined in `GHC.Base'
infixr 9 .
Now function application has higher precedence than any infix operator so
Prelude> reverse . tail . reverse [1,2,3,4]
becomes
Prelude> reverse . tail . (reverse [1,2,3,4])
which has wrong type when you try to apply composition. For composition to be correct you have to explicitly give composition higher precedence than function application which you can do by providing explicit parentheses.
Prelude> (reverse . tail . reverse) [1,2,3,4]
This solutions works but haskellers hate using parentheses. Here comes another operator $
which can save you in such places and make your code more readable than using parentheses.
When you see the type of $
Prelude> :i ($)
($) :: (a -> b) -> a -> b -- Defined in `GHC.Base'
infixr 0 $
You can clearly see that its precendence (0) is less than that of compostion (9) which gives you just the effect you want. You can just lower the precedence of last function application or replace function composition with $
.
Prelude> reverse . tail . reverse $ [1,2,3,4]
Prelude> reverse . tail $ reverse [1,2,3,4]
Prelude> reverse $ tail $ reverse [1,2,3,4]
This is perfectly fine as first operand of $
is a function and other is just a value of correct type.