For Opa, we used a variant on the technique. We had a rather complex Ast that was progressively refined through a number of passes. Each pass could remove or add cases, and we wanted to have type guarantees that ast nodes did not escape their scope. To do this, we used something along the lines of type 'variant Expr = | Let of ... | ... | Variant of 'variant and 'variant Foo = | ... In which ['variant] was instantiated with a polymorphic variant. This gave us considerable flexibility and generally avoided the problem of over-complicated error messages. You can find the full source code at https://github.com/MLstate/opalang/blob/master/compiler/opalang/surfaceAst.ml . Cheers, David