I've written compilers in C, C++, C#, Delphi, Java, ML and Lisp; targeting x86, x64, JVM and MSIL. I was maintainer of the Delphi front end at Borland / Embarcadero. Pattern matching isn't just nice; you end up with substantially better typechecking, and doesn't need ugly patterns like visitors with their inverted callback control flow, if you want to decouple e.g. type checking or code generation from your AST classes. Visitors are implicitly closed to extension unless you create very abstract visitors (and I've gone down that path, it's not pleasant) - you lose a big chunk of the extensibility objects give you over ADTs. (I'd prefer to use multimethods, but they are rarely available.)
I think persistent collections, along with nice syntax for updating immutable objects (i.e. cloning with a subset of changed attributes) are more practical than having undo available. Immutable data types remove the burden of worrying about who's going to modify the data type from under you, so it lets you share subgraphs more freely. You don't need to worry as much about coupling, because the things you give your state to can't modify it. A possible alternative is mutable collections with snapshots or freezing, but I think persistent collections are a better approach.