1. Don't expose these structures as native duck types. Instead, turn
them into StablePtr's and make them opaque in the Duck memory layout.
This is unpleasant, so I'm mentioning it only for completeness.
2. Declare the types in Haskell and use template Haskell to generate
the corresponding Duck datatypes and marshaling functions.
3. Declare the types in Duck and generate the corresponding Haskell
definitions and marshaling functions via pretty printing.
(3) is, of course, the coolest option. However, it requires a
bootstrapping step since the basic data types used by the compiler
would be generated by the compiler itself. These generated files
would be checked back into git so that the bootstrap is built into the
source code.
Geoffrey