3 ms·
Here's a slightly different Java example, for variety in the examples you're getting ;) I also recommend checking out the paper on object algebras [0], which ta
by Twisol 6y ago
Here's a slightly different Java example, for variety in the examples you're getting ;) I also recommend checking out the paper on object algebras [0], which takes this approach much further.
Notice that in some sense, the structure of the type is inferable from just the visitor interface. Everything else is just an explosion of boilerplate. (This is somewhat explained in the object algebras framework, as you can have multiple types accepting these visitors, just as much as having multiple visitors for the same type. In other words, this is related to the "expression problem".)
[0] https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf https://www.cs.utexas.edu/~wcook/Drafts/2012/ecoop2012.pdf
// An "external visitor", with the recursion external to the type being visited.
// The visitor is responsible for visiting each of the children.
public interface ExprVisitor1<Result> {
Result lit(double x);
Result add(Expr left, Expr right);
Result sub(Expr left, Expr right);
}
// An "internal visitor", with the recursion internal to the type being visited.
// I like these best, because the recursion can be turned into a tight loop
// (defunctionalize the continuation!) in a single place (in Expr).
// But you lose some expressivity, e.g. no short-circuiting the recursion.
// You can elaborate the recursion scheme of course, e.g.
// Result add(Supplier<Result> left, Supplier<Result> right);
// (but now it might be impossible to flatten the stack)
public interface ExprVisitor2<Result> {
Result lit(double x);
Result add(Result left, Result right);
Result sub(Result left, Result right);
}
public abstract class Expr {
private Expr() {}
public abstract <Result> Result visit(ExprVisitor2<Result> visitor);
public static Expr lit(final double x) {
return new Expr() {
public @Override <Result> Result visit(final ExprVisitor2<Result> visitor) {
return visitor.lit(x);
}
}
}
public static Expr add(final Expr left, final Expr right) {
return new Expr() {
public @Override <Result> Result visit(final ExprVisitor2<Result> visitor) {
return visitor.add(left.visit(visitor), right.visit(visitor));
}
}
}
public static Expr sub(final Expr left, final Expr right) {
return new Expr() {
public @Override <Result> Result visit(final ExprVisitor2<Result> visitor) {
return visitor.sub(left.visit(visitor), right.visit(visitor));
}
}
}
}