I\'m beginning to understand how the forall
keyword is used in so-called \"existential types\" like this:
data ShowBox = forall s. Show s =>
The reason why there are different uses of this keyword is that it's actually used in at least two different type system extensions: higher-rank types, and existentials.
It's probably best just to read about and understand those two things separately, rather than trying to get an explanation of why 'forall' is an appropriate bit of syntax in both at the same time.
With Existential-Quantification,
forall
s indata
definitions mean that, the value contained can be of any suitable type, not that it must be of all suitable types. -- yachiru's answer
An explanation of why forall
in data
definitions are isomorphic to (exists a. a)
(pseudo-Haskell) can be found in wikibooks's "Haskell/Existentially quantified types".
The following is a brief verbatim summary:
data T = forall a. MkT a -- an existential datatype
MkT :: forall a. a -> T -- the type of the existential constructor
When pattern-matching/deconstructing MkT x
, what is the type of x
?
foo (MkT x) = ... -- -- what is the type of x?
x
can be any type (as stated in the forall
), and so it's type is:
x :: exists a. a -- (pseudo-Haskell)
Therefore, the following are isomorphic:
data T = forall a. MkT a -- an existential datatype
data T = MkT (exists a. a) -- (pseudo-Haskell)
My simple interpretation of all this, is that "forall
really means 'for all'".
An important distinction to make is the impact of forall
on the definition versus function application.
A forall
means the definition of the value or function must be polymorphic.
If the thing being defined is a polymorphic value, then it means that the value must be valid for all suitable a
, which is quite restrictive.
If the thing being defined is a polymorphic function, then it means that the function must be valid for all suitable a
, which isn't that restrictive because just because the function is polymorphic doesn't mean the parameter being applied have to be polymorphic. That is, if the function is valid for all a
, then conversely any suitable a
can be applied to the function. However, the type of the parameter can only be chosen once in the function definition.
If a forall
is inside the function parameter's type (i.e., a Rank2Type
) then it means the applied parameter must be truly polymorphic, to be consistent with the idea of forall
means definition is polymorphic. In this case, the type of the parameter can be chosen more than once in the function definition ("and is chosen by the implementation of the function", as pointed out by Norman)
Therefore, the reason why existential data
definitions allows any a
is because the data constructor is a polymorphic function:
MkT :: forall a. a -> T
kind of MkT :: a -> *
Which means any a
may be applied to the function. As opposed to, say, a polymorphic value:
valueT :: forall a. [a]
kind of valueT :: a
Which means that the definition of valueT must be polymorphic. In this case, valueT
can be defined as empty list []
of all types.
[] :: [t]
Even though the meaning for forall
is consistent in ExistentialQuantification
and RankNType
, existentials has a difference since the data
constructor can be used in pattern matching. As documented in the ghc user guide:
When pattern matching, each pattern match introduces a new, distinct, type for each existential type variable. These types cannot be unified with any other type, nor can they escape from the scope of the pattern match.