In Haskell I can define following data type:
data Tree = Empty
| Leaf Int
| Node Tree Tree
and then write polymorphic function like this:
depth :: Tree -> Int
depth Empty = 0
depth (Leaf n) = 1
depth (Node l r) = 1 + max (depth l) (depth r)
In Java I can emulate algebraic data types with interfaces:
interface Tree {}
class Empty implements Tree {}
class Leaf implements Tree { int n; }
class Node implements Tree { Tree l; Tree r; }
But if I try to use Haskell-like polymorphism, I get an error:
int depth(Empty node) {
return 0;
}
int depth(Leaf node) {
return 1;
}
int depth(Node node) {
return 1 + Math.max(depth(node.l), depth(node.r)); // ERROR: Cannot resolve method 'depth(Tree)'
}
Correct way to overcome this is to put method depth() to each class. But what if I don’t want to put it there? For example, method depth() may be not directly related to Tree and adding it to class would break business logic. Or, even worse, Tree may be written in 3rd party library that I don’t have access to. In this case, what is the simplest way to implement ADT-like polymorpism?
Just in case, for the moment I’m using following syntax, which is obviously ill-favored:
int depth(Tree tree) {
if (tree instanceof Empty) depth((Empty)tree)
if (tree instanceof Leaf) depth((Leaf)tree);
if (tree instanceof Node) depth((Node)tree);
else throw new RuntimeException("Don't know how to find depth of " + tree.getClass());
}
Try something like this.
Sorry, my Java is very rusty. If, unlike me, you can remember the syntax, you could use Java generics to refine
ObjecttoIntegeror whatever class the method you’re writing needs. But you can’t (can you?) return primitive types, sorry.Note that in
depth()I have to manually recurse (callfold()) on theTreeparameters. You could instead choose to recurse on them upfront inNode.fold()(and changeTreeFolderaccordingly), but then you have to recurse — you can’t choose to recurse only into the left subtree, should you wish to. (In Haskell we don’t have to make that trade-off thanks to laziness.)