Traditional wisdom says that you shouldn't use `instanceof`, because downcasting is bad and you should work with an interface uniformly implemented by any particular subclass. The Visitor pattern accomplishes this by giving the shared supertype a `match` method accepting, effectively, a bunch of callbacks, and each subclass just chooses which callback to invoke.
In algebraic type notation, this pattern replaces a function returning a sum type, X -> A + B + C, with a function accepting a callback that accepts a sum type, `X -> (A + B + C -> Y) -> Y`. But function accepting a sum type is the same as a product of functions, so you have `X -> (A -> Y, B -> Y, C -> Y) -> Y`. The product of functions is the visitor, and `X` is the thing you're visiting.
Traditional wisdom is correct when you have an open family of subclasses (i.e. you don't know, and shouldn't know, precisely how many subclasses there are). But for a closed family, it's just unnecessary; you're blinding yourself from information you already possessed.
In algebraic type notation, this pattern replaces a function returning a sum type, X -> A + B + C, with a function accepting a callback that accepts a sum type, `X -> (A + B + C -> Y) -> Y`. But function accepting a sum type is the same as a product of functions, so you have `X -> (A -> Y, B -> Y, C -> Y) -> Y`. The product of functions is the visitor, and `X` is the thing you're visiting.
Traditional wisdom is correct when you have an open family of subclasses (i.e. you don't know, and shouldn't know, precisely how many subclasses there are). But for a closed family, it's just unnecessary; you're blinding yourself from information you already possessed.