JSON GADT : https://github.com/OCamlPro/ocplib-json-typed/blob/0d9e9cde7...
Mirage/repr, uses GADT's for representing OCaml types as runtime values which are used for implementing dynamic polymorphism - https://github.com/mirage/repr/blob/main/src/repr/type.ml
type Term = {kind: 'lit', value: number} | {kind: 'pair', left: Term, right: Term};
function pair(left: Term, right: Term): Term & {kind: 'pair'} {
return {kind: 'pair', left, right};
}
function lit(n: number): Term & {kind: 'lit'} {
return {kind: 'lit', value: n};
}
let t: Term = pair(
pair(lit(1), lit(2)),
lit(3)
);[1] https://wiki.haskell.org/Existential_type#Dynamic_dispatch_m...
The other subtle thing with GADTs is that the type information must flow back from the matched case to the type parameter: if you match an Ast<R> and get Mul, you know that R=Int. And that part is impossible to do fully in a language that doesn't have higher-kinded types, because you not only need to be able to know that you can pass an Int where an R was expected, but also that you can pass an Ast<Int> where an Ast<R> is expected, or return a List<Int> where a List<R> is expected, or....
Not that Haxe is mainstream, but it does target mainstream languages.