Why use Algebraic DataTypes? Can't regular OO constructs get the job done?
Yes. And no. "Yes" because in the end jADT just generates pretty ordinary Java Visitor code. "No" because that ordinary code expresses a design approach that is atypical in OO programming.
It's worth explaining the difference.
In OO it's common to have a class hierarchy where the base class or base interface declares some methods and subclasses override/implement them as needed. OO hierarchies make it easy to add new "cases" - new subclasses. You just create the new class that extends/implements and move on. But when you need to add a new operation - a new method - it's a bigger deal. You need to open up the source for the base class or interface, add the method declaration there, then (potentially) open up all the subclasses to implement variations.
ADTs turn that 180 degrees around. With an ADT the "hierarchy" is sealed against extension. You can't add new cases without opening up the base source. But you can very, very easily add operations without even having access to the ADT's source.
A concrete example might help. In language processing it is common to parse raw source code into an Abstract Syntax Tree (AST) - a tree shaped structure that captures the essence of the source but strips out whitespace, comments, punctuation, and other syntactic noise. Once you've got an AST there are many things you might want to do with it: pretty print it, interpret it, etc.
In the standard OO approach you have a root class that declares methods for print, interpret, etc. It's easy to extends this language by adding another node in the hierarchy, but it's hard to add additional operations on the AST. If a separate team wants to create a static analysis that finds errors or does type checking then they have a problem if they don't have access to the AST's source. They either have to do error prone instanceof style checks or they have to do an error prone re-implementation of the parser to generate an instances of an AST that meets their needs.
If the original AST were defined using ADTs then the third party would do just fine. They can add operations that use the ADTs matching capability without having to touch any source that they don't own.
Of course, if the AST is defined using ADTs then it's hard for a third party to extend the language.
But in practice it's FAR more common for third parties to want to add operations on an existing AST than to want to change the definition of a language.
The choice of ADT vs OO style inheritance hierarchy comes down to which direction needs extension most: if you need to add cases, choose OO. If you need to add operations, choose ADTs.