The following built-ins control macro expansion:
define a macro for the given TermClass. The transformation will be performed by the predicate TransPred.
erase a currently defined macro for TermClass. This can only be done in the module where the definition was made.
retrieve information about currently defined visible macros.
Macros are selectively applied only to terms of the specified class. TermClass can take two forms:
At transformation time, the system will call TransPred in the module where define_macro/3 was invoked. The term to transform is passed as the first argument, the second is a free variable which the transformation predicate should bind to the transformed term, and the optional third argument is the module where the term is read or written.trans_function(OldTerm, NewTerm [, Module]) :- ... .
Options is a list which may be empty (in this case the macro defaults to a local read term macro) or contain specifications from the following categories:
Here is an example of a conditional read macro:
If the transformation function fails, the term is not transformed. Thus, a(1, zzz) is transformed into b(zzz) but a(-1, zzz) is not transformed. The arguments are transformed bottom-up. It is possible to protect the subterms of a transformed term by specifying the flag protect_arg.[eclipse 1]: [user]. trans_a(a(X,Y), b(Y)) :- % transform a/2 into b/1, number(X), % but only under these X > 0. % conditions :- define_macro(a/2, trans_a/2, []). user compiled traceable 204 bytes in 0.00 seconds yes. [eclipse 2]: read(X). a(1, hello). X = b(hello) % transformed yes. [eclipse 3]: read(X). a(-1, bye). X = a(-1, bye) % not transformed yes.
A term can be protected against transformation by quoting it with the ``protecting functor'' (by default it is no_macro_expansion/1):
Note that the protecting functor is itself defined as a macro:[eclipse 4]: read(X). a(1, no_macro_expansion(a(1, zzz))). X = b(a(1, zzz)).
A macro is by default only visible in the module where it has been defined. When it is defined inside a module interface, then it is copied to all other modules that contain a use_module/1 for this module. The transformation function should be exported in this case and be defined in the module interface as well.trprotect(no_macro_expansion(X), X). :- define_macro(no_macro_expansion/1, trprotect/2, [global, protect_arg]).
A macro can also be made visible in all modules by specifying the global option in the option list. As usual, local definitions hide global ones. The global flag macro_expansion can be used to disable macro expansion globally, e.g. for debugging purposes. Use set_flag(macro_expansion, off) to do so.
The next example shows the use of a type macro. Suppose we want to represent integers as s/1 terms:
When we want to convert the s/1 terms back to normal integers so that they are printed in the familiar form, we can use a write macro. Note that we first erase the read macro for integers, otherwise we would get unexpected effects since all integers occurring in the definition of tr_s/2 would turn into s/1 structures:[eclipse 1]: [user]. tr_int(0, 0). tr_int(N, s(S)) :- N > 0, N1 is N-1, tr_int(N1, S). :- define_macro(type(integer), tr_int/2, []). yes. [eclipse 2]: read(X). 3. X = s(s(s(0))) yes.
[eclipse 3]: erase_macro(type(integer)). yes. [eclipse 4]: [user]. tr_s(0, 0). tr_s(s(S), N) :- tr_s(S, N1), N is N1+1. :- define_macro(s/1, tr_s/2, [write]). yes. [eclipse 2]: write(s(s(s(0)))). 3 yes.