What is happening here is that there is a special typing rule in GHC 7 which only applies to the standard ($) operator. Simon Peyton-Jones explains this behavior in a reply on the GHC users mailing list:

This is a motivating example for type inference that can deal with
impredicative types. Consider the type of ($):

($) :: forall p q. (p -> q) -> p -> q

In the example we need to instantiate p with (forall s. ST s a), and that's what
impredicative polymorphism means: instantiating a type variable with a
polymorphic type.

Sadly, I know of no system of reasonable complexity that can typecheck
[this] unaided. There are plenty of complicated systems, and I have
been a co-author on papers on at least two, but they are all Too
Jolly Complicated to live in GHC. We did have an implementation of
boxy types, but I took it out when implementing the new typechecker.
Nobody understood it.

However, people so often write

runST $ do ...

that in GHC 7 I implemented a special typing rule, just for infix uses of ($). Just think of (f $ x) as a new
syntactic form, with the obvious typing rule, and away you go.

The runST $ do { ... } pattern is so common, and the fact that it normally wouldn't type-check is so annoying, that GHC included some ST-specific type-checking hacks to make it work. Those hacks are probably firing here for the ($) version, but not the (.) version.

Interesting point. It is probably enough to simply drop the ($) as soon as it is seen that it is applied to 2 arguments. Should be easily verifiable by replacing it with a custom function that does the same as ($), and look if the type checker would complain then.
– IngoFeb 27 '12 at 18:37