The (.).(.) Operator is sometimes assigned an alias:
(.:) = (.).(.)
You can view it as (.) , Only it works when the second function takes two arguments. So this works, for example:
sqrtsum = sqrt .: (+) -- sqrtsum 4 5 ==> 3.0
It takes two numbers, sums them up, and then takes the square root of the sum. The alias type .: Makes visual sense, since you can imagine that a colon representing a function of two arguments is associated with a function of one argument.
If you want, you can view the type signature (.) As follows:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
This means that (.) Performs two functions a -> b and b -> c and "connects them together" and returns a function from a directly to c . The operator (.:) works similarly - you can write its signature like
(.:) :: (b -> c) -> (a1 -> a2 -> b) -> (a1 -> a2 -> c)
What he does is that for one function a1 -> a2 -> b and one function b -> c it returns a function that goes directly from a1 and a2 to c .
If you want to check this type for yourself, you can go your way to (.:) with a signature for (.) . I will not do this for you, partly because it can become a wall of text and partly because it is a great exercise for you to reason about your code! If you need a place to start, remember that
(.) :: (b -> c) -> (a -> b) -> (a -> c)
In expression
(.).(.)
which can also be written as
(.) (.) (.)
the two argument functions in (.) ( a -> b and b -> c ) are themselves (.) ), so you can replace a lot of a and b and c with what they actually represent!