The following introduction is provided to ensure you understand how I reached the problem (to not fall prey to the XY problem):
I am working on a program which turns a parser in Parsec-like DSL into an actual LL(1) parser (and in the future similarly for LALR(1) or others).
It basically works as follows:
- The DSL consists of functions which together build up a GADT. The result is a datatype which might contain cycles ('tying the knot'-style).
- Data.Reify is used to turn this into a graph representation ('untying' the knot).
- Perform the necessary transformations on this graph to turn it into a LL(1) parsing table.
- Construct the parser which will use this table.
Because we want to be able to use the data that is recognized while parsing to construct some kind of result, we need to pass on functions through steps (1.) to (4.).
In steps 1, 2, 3 we can get away with using an existential datatype. It's only when actually running the parser, that I found myself requiring Data.Dynamic
and its dynApp
to combine the results. We know that the types line up (since in step (1) the GADT construction is type-checked), but I did not figure out how to use the existential types in any other way (as each of the parsing steps might have a very different type).
The current procedure thus 'works' but requires Dynamic. Also, the whole parser, while based on a written function definition, will be constructed at runtime. Enter Template Haskell: Since the parser function is defined in a different module, it ought to be able to construct the parser at compile-time.
However, there is no Lift
instance for Dynamic
!
Furthermore, attempting to directly lift the existential types (i.e. require a Lift
constraint on them) instead also does not work, as these are almost always functions!
How can we lift a GADT containing either Dynamic
s or Typeable a => a
's into a TemplateHaskell quotation?
Or is there another approach to be able to handle this situation?