Skip to content

Instantly share code, notes, and snippets.

@mndrix
Last active August 14, 2018 04:38
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mndrix/d445770f5a0bd83aead6 to your computer and use it in GitHub Desktop.
Save mndrix/d445770f5a0bd83aead6 to your computer and use it in GitHub Desktop.
Prolog macros tips

Tips for writing macros in SWI Prolog. This should eventually be expanded into a full blog post:

Only expand macros when requested

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.

Make term expansion a separate predicate

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment