I believe the problem is that someone could be using 2 different types which are instances of Intermediate in this composition.
No the problem is that Haskell can no longer derive from the signature what a to use. Imagine that there are two Intermediate types:
instance Intermediate Char where
# …
instance Intermediate Bool where
# …
now there are two implementations for h:
h :: Char -> Int
h = f . (g :: Char -> Char)
or:
h :: Char -> Int
h = f . (g :: Char -> Bool)
there can be an infinite number of Intermediate types that can be used. The problem is that Haskell can not tell, based on the type signature what type to use.
We can give it a type hint, but that of course means that the intermediate type is fixed.
A simple way to fix this is making use of asTypeOf :: a -> a -> a. This is basically a const function, but where the two parameters have the same type. This is thus used to add a hint what type to use, for example:
h :: Intermediate a => a -> Char -> Int
h a x = f (g x `asTypeOf` a)
Here the value a parameter is thus not of any importance, this is a way to "inject" the type that will be used as type for the result of g and the parameter of f.
If you thus later use h, you can work with:
h (undefined :: Char) 'a'
to specify that f should have type Char -> Char, and g should have type Char -> Int.
Like @leftroundabout and @DanielWagner say, a more clean solution without making use of such dummy variable, is adding the type variable in the signature:
{-# LANGUAGE AllowAmbiguousTypes, ScopedTypeVariables, TypeApplications #-}
h :: forall a. Intermediate a => Char -> Int
h = f . g @ a
then we can use h with a type variable with:
h @ Char 'a'