std::list<Parent *>
then some of those pointers may actually point at a Child. The client code doesn't care. This is an important kind of polymorphism.In Haskell, you can't reasonably express this with typeclasses, which surprises folks new to Haskell. You can still express it (as I mentioned), it just takes a different form (and precisely which form is best can vary with other considerations).
data P = forall a . Parent a => P a
type PList = [P]
where Parent is a type class.You have to be a bit more explicit when using a Child in the position of a Parent when adding to the list and you have to use (fully polymorphic!) pattern matches to extract elements from the list, but personally I consider this a good thing as it's more explicit.
Aside: Existential types is what OOP interfaces are -- and interfaces are often encoded as such in language semantics; see e.g. Types and Programming Languages (Pierce).
EDIT: Typos in code -- unfortunately my Haskell is a little rusty :(.
For what it's worth, I do think people underestimate the applicability of closed sum types.
This is the case for all typed programming languages, not just Haskell. So-called dynamic languages like Python, Ruby or Javascript are merely static languages with but a single type[0].
[0] http://existentialtype.wordpress.com/2011/03/19/dynamic-lang...