Here's a function polymorphic in 3 types:
:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
and here a non polymorphic function:
:t Data.Char.digitToInt
Data.Char.digitToInt :: Char -> Int
If we apply the former to the latter, we get a function polymorphic in 1 type:
:t (.) Data.Char.digitToInt
(.) Data.Char.digitToInt :: (a -> Char) -> a -> Int
which means that (.) was "instantiated" (I'm not sure this is the correct term; as a C++ programmer, I'd call it so) with b === Char and c === Int, so the signature of the (.) that gets applied to digitToInt is the following
(Char -> Int) -> (a -> Char) -> a -> Int
My question is: is there a way to have this signature printed on screen, given (.), digitToInt and the "information" that I want to apply the former to the latter?
For who's interested, this question was earlier closed as duplicate of this one.

Other answers require the help of functions that have been defined with artificially restricted types, such as the
asTypeOffunction in the answer from HTNW. This is not necessary, as the following interaction shows:This exploits the lack of polymorphism in the lambda-binding that is implicit in the definition of
asAppliedTo. Both occurrences offin its body must be given the same type, and that is the type of its result. The functionconstused here also has its natural typea -> b -> a: