(Make sure you understand higher-order functions and currying, read Learn You a Haskell chapter on higher-order functions, then read difference between . (dot) and $ (dollar sign) and function composition (.) and function application ($) idioms)
($) is just a function application, f $ x is equivalent to f x. But that's good, because we can use explicit function application, for example:
map ($2) $ map ($3) [(+), (-), (*), (**)] -- returns [5.0,1.0,6.0,9.0]
which is equivalent to:
map (($2) . ($3)) [(+), (-), (*), (**)] -- returns [5.0,1.0,6.0,9.0]
Check the type of ($): ($) :: (a -> b) -> a -> b. You know that type declarations are right-associative, therfore the type of ($) can also be written as (a -> b) -> (a -> b). Wait a second, what's that? A function that receives an unary function and returns an unary function of the same type? This looks like a particular version of an identity function id :: a -> a. Ok, some types first:
($) :: (a -> b) -> a -> b
id :: a -> a
uncurry :: (a -> b -> c) -> (a, b) -> c
uncurry ($) :: (b -> c, b) -> c
uncurry id :: (b -> c, b) -> c
When coding Haskell, always look at types, they give you lots of information before you even look at the code. So, what's a ($)? It's a function of 2 arguments. What's an uncurry? It's a function of 2 arguments too, the first being a function of 2 arguments. So uncurry ($) should typecheck, because 1st argument of uncurry should be a function of 2 arguments, which ($) is. Now try to guess the type of uncurry ($). If ($)'s type is (a -> b) -> a -> b, substitute it for (a -> b -> c): a becomes (a -> b), b becomes a, c becomes b, therefore, uncurry ($) returns a function of type ((a -> b), a) -> b. Or (b -> c, b) -> c as above, which is the same thing. So what does that type tells us? uncurry ($) accepts a tuple (function, value). Now try to guess what's it do from the type alone.
Now, before the answer, an interlude. Haskell is so strongly typed, that it forbids to return a value of a concrete type, if the type declaration has a type variable as a return value type. So if you have a function with a type a -> b, you can't return String. This makes sense, because if your function's type was a -> a and you always returned String, how would user be able to pass a value of any other type? You should either have a type String -> String or have a type a -> a and return a value that depends solely on an input variable. But this restriction also means that it is impossible to write a function for certain types. There is no function with type a -> b, because no one knows, what concrete type should be instead of b. Or [a] -> a, you know that this function can't be total, because user can pass an empty list, and what would the function return in that case? Type a should depend on a type inside the list, but the list has no “inside”, its empty, so you don't know what is the type of elements inside empty list. This restriction allows only for a very narrow elbow room for possible functions under a certain type, and this is why you get so much information about a function's possible behavior just by reading the type.
uncurry ($) returns something of type c, but it's a type variable, not a concrete type, so its value depends on something that is also of type c. And we see from type declaration that the function in the tuple returns values of type c. And the same function asks for a value of type b, which can only be found in the same tuple. There are no concrete types nor typeclasses, so the only thing uncurry ($) can do is to take the snd of a tuple, put it as an argument in function in fst of a tuple, return whatever it returns:
uncurry ($) ((+2), 2) -- 4
uncurry ($) (head, [1,2,3]) -- 1
uncurry ($) (map (+1), [1,2,3]) -- [2,3,4]
There is a cute program djinn that generates Haskell programs based on types. Play with it to see that our type guesses of uncurry ($)'s functionality is correct:
Djinn> f ? a -> a
f :: a -> a
f a = a
Djinn> f ? a -> b
-- f cannot be realized.
Djinn> f ? (b -> c, b) -> c
f :: (b -> c, b) -> c
f (a, b) = a b
This shows, also, that fst and snd are the only functions that can have their respective types:
Djinn> f ? (a, b) -> a
f :: (a, b) -> a
f (a, _) = a
Djinn> f ? (a, b) -> b
f :: (a, b) -> b
f (_, a) = a