Hello Tim,
I don't know the answers to your questions exactly, but I've played around with something that I think might be related, so I thought I'd share. The example code is here:
This module contains a function that compiles (at runtime) a Haskell module represented as a String to the value of whatever `main` happened to be defined in this module.
Actually, in this case the expression is taken as a `Doc` , which is the result of pretty printing something, but this doc is simply "show"-ed to make a string (see `modText`).
The function works in roughly two steps:
1. Compile the module:
1.1. Setup some compiler flags, this has to do with the dependencies of the module (i.e., what packages it depends on, etc)
1.2. Define a "target": this is what GHC will be compiling. There is a bit of weirdness here: GHC can take the input to compile either from a text file, or from an in-memory buffer. The second is what we want here. Unfortunately, for some reason GHC still insists on there being a file around (its contents is completely irrelevant) I think it just want to check when it was last modified :-) This is why we create an empty file. This is something that should probably be fixed in GHC.
1.3 Load all the targets: this is what will actually compile the module
2. Get the value of `main` in this module: this is done in the `Succeed` branch of the case, where we create an expression `M.main` and tell GHC to evaluate it.
Depending on how you need things to be setup, just the second step might be enough (i.e., call `compileExpr`). You'd still need to do enough to tell GHC in what context it will be compiling the expression though.
I am not an expert on this topic, but I'd be happy to try to answer more questions if I can.
-Iavor