[racket] Macro design question: best way to interpret an expression multiple ways
I have two libraries of combinators meant to be used as targets for a
language semantics. I'm implementing the semantics using macros; e.g.
#'(interp (+ 4 5)) => #'(((const 4) . &&& . (const 5)) . >>> . add)
where `interp' is a macro and `=>' means macro expansion.
Here's the tricky part. I have to interpret the language using *both*
combinator libraries, not just one; e.g. I need #'(interp (+ 4 5)) to
expand to both of these:
#'(((const/bot 4) . &&&/bot . (const/bot 5)) . >>>/bot . add/bot)
#'(((const/pre 4) . &&&/pre . (const/pre 5)) . >>>/pre . add/pre)
I could have #'(interp (+ 4 5)) expand to something like
#'(list (interp/bot (+ 4 5)) (interp/pre (+ 4 5)))
But expanding twice is terrible manners when the expression contains macros.
(Originally, I had super-combinators that did the job of both */bot and
*/pre combinators. These super-combinators were complicated and messy,
especially when used in recursion, which is why I'm moving the
"interpret the language two ways" job into the macro system and hoping
it's nicer. It should also generate faster code, and possibly allow type
checking on one of the interpretations.)
The best idea I've had so far is to have (interp e) expand to uses of
generic `&&&' and `>>>' combinators, apply `local-expand', and do a
syntax tree search-and-replace that does #'&&& => #'&&&/bot, etc. Is
there another way, though, that doesn't run afoul of macro security?
Neil ⊥