Tips for writing macros in SWI Prolog. This should eventually be expanded into a full blog post:
For each module that defines a macro, define a predicate like:
wants_my_fancy_macro :-
prolog_load_context(module, Module),
Module \== my_module, % don't expand macros in our own code
current_predicate(Module:my_module_macro_sentinel/0), % prevent autoloading
predicate_property(Module:my_module_macro_sentinel,imported_from(my_module)).
Be sure to export my_module_macro_sentinel/0
from your module so that you can test for its existence. Only expand macros if the loading module wants your macro:
user:term_expansion(Old,New) :-
wants_my_fancy_macro,
expand_my_macro(Old,New).
TODO: factor out wants_my_fancy_macro/0
to wants_macro_from(SourceModule,SentinelIndicator)
and put it in a pack so the code can be reused across macro projects.
Don't put your term expansion code directly in term_expansion/2
or goal_expansion/2
. Instead, put it in a private predicate (expand_my_macro/2
) and call that predicate from the system predicates. This makes it much easier to write tests for your macro and to play with it at the top level.