During loading of source code, all terms being read in are subject to
term expansion. Grammar rules is a special, built-in case of this
mechanism. By defining the hook predicates
goal_expansion/5, you can
specify any desired transformation to be done as clauses are loaded.
Term expansions are added by defining clauses for the following hook predicate. Such clauses should follow the pattern:
:- multifile user:term_expansion/6. user:term_expansion(Term1, Layout1, Ids, Term2, Layout2, [token|Ids]) :- ... nonmember(token, Ids), token_expansion(Term1, Layout1, Term2, Layout2), !.
where token_expansion/4 should be a predicate defining how to
transform a given Term1 into Term2. The hook is called for every
Term1 read, including at end of file, represented as the
end_of_file. If it succeeds, Term2 is used
for further processing; otherwise, the default grammar rule expansion
is attempted. It is often useful to let a term expand to a list of
directives and clauses, which will then be processed sequentially.
A key idea here is Ids, which is used to look up what expansions have already been applied. The argument is supposed to be a list of tokens, each token uniquely identifying an expansion. The tokens are arbitrary atoms, and are simply added to the input list, before expansions recursively are applied. This token list is used to avoid cyclic expansions.
The other arguments are for supporting source-linked debugging; see the reference page for details. See mpg-ref-term_expansion.
Please note: term expansions are global, i.e. they affect
all code that are compiled or consulted. In particular a term expansion
is not affected by module imports. Care should be taken so that a term
expansion does not unintentionally affect some unrelated source
goal_expansion/5 provides a more robust, and module
aware, way to transform individual goals.
Goal expansions are added by defining the hook predicate:
M:goal_expansion(Goal1, Layout1, Module, Goal2, Layout2) :- ...
which should define how to transform a given Goal1 into Goal2. Expansions are per module and should be defined in the module M in which Goal1 is locally defined. It is called for every goal occurring in a clause being loaded, asserted, or meta-called. If it succeeds, Goal2 is used for further processing, and may be arbitrarily complex.
Please note: In general, the goal expansion can happen both at compile time and at runtime (and sometimes both, even for the same goal). For this reason the code that implements goal expansion should be present both at compile time and at runtime.
The other arguments are for supporting source-linked debugging and passing the source module; see the reference page for details.
To invoke term expansion from a program, use:
?- expand_term(Term1, Term2).
which transforms Term1 into Term2 using the built-in (for grammar rules) as well as user-defined term expansion rules. See mpg-ref-goal_expansion.