I spent so long at university writing out GoF style stuff (I want to say crap) like the visitor pattern in java. Now I write ruby. Those are hours and days I will never get back. I remember thinking at the time, "Why am I doing this? Surely this is what computers are for?"
I guess it's all education in the end. At least now I appreciate the value of the tools I have.
Not further than Clojure's multimethods. They dispatch on the value of an arbitrary function you write. This can be anything; it's not even restricted to types. Couple this with Clojure's ad hoc hierarchy system and even Haskell's types seem limited by comparison.
that means that the visitor pattern can be replaced with multiple dispatch (true) but neither map nor fmap imply that (and in fact many languages have the latter but not the former)
Clojure has both map and multimethods. It's trivial to map over a collection and dispatch to a different implementation for every element in the collection. With multiple collections, this extends to multiple dispatch over the corresponding elements in each collection.
Double-dispatch seems to be equivalent to Haskell's pattern matching.
Since Haskell does not have sub-typing, everything has the same runtime type. However, you can easily combine different types into a single algebraic data type and then dispatch by pattern matching against that type.
This probably isn't exactly the same as double-dispatch in other languages, but it seems to be very similar and to serve the same purpose.
Implementation details are the least valuable part design patterns. Implementing a visitor via map doesn't some how make it not a visitor. You still have to have some way of referring to what is going on when you do visitor like things.
For example, the Visitor pattern can be naturally replaced with map and fmap in Haskell, which are far more powerful.