Correct me if I\'m wrong, but it seems like algebraic data types in Haskell are useful in many of the cases where you would use classes and inheritance in OO languages. But
Another (more or less) intuitive way of looking at data types and typeclasses versus object oriented classes is the following:
A class Foo in an OO language represents both a concrete type Foo as well as the class of all Foo-types: those which are directly or indirectly derived from Foo.
In OO languages, you just happen to implicitly program against the class of Foo-types which allows you to "extend" Foo.
Okay, by "open" here you're meaning "can be derived from" and not open in the sense of Ruby and Smalltalk, where you can extend a class with new methods at run-time, right?
In any case, notice two things: first, in most OO languages that are primarily inheritance-based, there is a way to declare a class to restrict it's ability to be inherited. Java has "final", and there are hacks for this in C++. So on that, it's just making as the default an option in other OO languages.
Second, you can still create a new type that uses the closed ADT and adds other methods or different implementations. So you aren't really restricted in that way. Again, they seem to formally have the same strength; what you can express in one can be expressed in the other.
The real thing is that functional programming really is a different paradigm ("pattern"). If you go into it with the expectation that it ought to be like an OO language, you'll be surprised regularly.