regarding "why aren’t newtypes good enough”:
newtypes are fine in simple cases, but for more complex cases, such as an AST, you can’t just change the type without changing the containing types too. For example, its always fun when you need to deal with changing the json serialization of some data that is deeply nested.
This comes up more often than you might think; for example, you may want to change the way data is generated for an Arbitrary instance embedded in another piece of data.
As an aside, you may find this interesting: Monad Transformers and Effects with Backpack