I\'m beginning to understand how the forall keyword is used in so-called \"existential types\" like this:
data ShowBox = forall s. Show s =>
Here is a quick and dirty explanation in plain terms that you're likely to be already familiar with.
The forall keyword is really only used in one way in Haskell. It always means the same thing when you see it.
Universal quantification
A universally quantified type is a type of the form forall a. f a. A value of that type can be thought of as a function that takes a type a as its argument and returns a value of type f a. Except that in Haskell these type arguments are passed implicitly by the type system. This "function" has to give you the same value no matter which type it receives, so the value is polymorphic.
For example, consider the type forall a. [a]. A value of that type takes another type a and gives you back a list of elements of that same type a. There is only one possible implementation, of course. It would have to give you the empty list because a could be absolutely any type. The empty list is the only list value that is polymorphic in its element type (since it has no elements).
Or the type forall a. a -> a. The caller of such a function provides both a type a and a value of type a. The implementation then has to return a value of that same type a. There's only one possible implementation again. It would have to return the same value that it was given.
Existential quantification
An existentially quantified type would have the form exists a. f a, if Haskell supported that notation. A value of that type can be thought of as a pair (or a "product") consisting of a type a and a value of type f a.
For example, if you have a value of type exists a. [a], you have a list of elements of some type. It could be any type, but even if you don't know what it is there's a lot you could do to such a list. You could reverse it, or you could count the number of elements, or perform any other list operation that doesn't depend on the type of the elements.
OK, so wait a minute. Why does Haskell use forall to denote an "existential" type like the following?
data ShowBox = forall s. Show s => SB s
It can be confusing, but it's really describing the type of the data constructor SB:
SB :: forall s. Show s => s -> ShowBox
Once constructed, you can think of a value of type ShowBox as consisting of two things. It's a type s together with a value of type s. In other words, it's a value of an existentially quantified type. ShowBox could really be written as exists s. Show s => s, if Haskell supported that notation.
runST and friends
Given that, how are these different?
foo :: (forall a. a -> a) -> (Char,Bool)
bar :: forall a. ((a -> a) -> (Char, Bool))
Let's first take bar. It takes a type a and a function of type a -> a, and produces a value of type (Char, Bool). We could choose Int as the a and give it a function of type Int -> Int for example. But foo is different. It requires that the implementation of foo be able to pass any type it wants to the function we give it. So the only function we could reasonably give it is id.
We should now be able to tackle the meaning of the type of runST:
runST :: forall a. (forall s. ST s a) -> a
So runST has to be able to produce a value of type a, no matter what type we give as a. To do so, it uses an argument of type forall s. ST s a which certainly must somehow produce the a. What's more, it must be able to produce a value of type a no matter what type the implementation of runST decides to give as s.
OK, so what? The benefit is that this puts a constraint on the caller of runST in that the type a cannot involve the type s at all. You can't pass it a value of type ST s [s], for example. What that means in practice is that the implementation of runST is free to perform mutation with the value of type s. The type guarantees that this mutation is local to the implementation of runST.
The type of runST is an example of a rank-2 polymorphic type because the type of its argument contains a forall quantifier. The type of foo above is also of rank 2. An ordinary polymorphic type, like that of bar, is rank-1, but it becomes rank-2 if the types of arguments are required to be polymorphic, with their own forall quantifier. And if a function takes rank-2 arguments then its type is rank-3, and so on. In general, a type that takes polymorphic arguments of rank n has rank n + 1.