What exactly is the difference between these? I think I understand how existential types work, they are like having a base class in OO without a way to down cast. How are un
Bartosz Milewski in his book offers some good insight about why Haskell doesnt need an existential quantifier:
in pseudo-Haskell:
(exists x. p x x) -> c ≅ forall x. p x x -> cIt tells us that a function that takes an existential type is equivalent to a polymorphic function. This makes perfect sense, because such a function must be prepared to handle any one of the types that may be encoded in the existential type. It’s the same principle that tells us that a function that accepts a sum type must be implemented as a case statement, with a tuple of handlers, one for every type present in the sum. Here, the sum type is replaced by a coend, and a family of handlers becomes an end, or a polymorphic function.
Hence, an example of an existentially quantified type in Haskell is
data Sum = forall a. Constructor a (i.e. forall a. (Constructor_a:: a -> Sum) ≅ Constructor:: (exists a. a) -> Sum)
which can be thought of as a sum
data Sum = int | char | bool | .... In contrast, an example of a universally quantified type in Haskell is
data Product = Constructor (forall a. a)
which can be though of as a product data Product = int char bool ....