next up previous index
Next: Definite Clause Grammars Up: ECLiPSe Macros Previous: Introduction

Using the macros

The following built-ins control macro expansion:

define_macro(+TermClass, +TransPred, +Options)

define a macro for the given TermClass. The transformation will be performed by the predicate TransPred.

erase_macro(+TermClass)

erase a currently defined macro for TermClass. This can only be done in the module where the definition was made.

current_macro(?TermClass, ?TransPred, ?Options, ?Module)

retrieve information about currently defined visible macros.

Macros are selectively applied only to terms of the specified class. TermClass can take two forms:

Name/Arity
transform all terms with the specified functor    
type(Type)
transform all terms of the specified type, where Type is one of compound, string, integer, rational, real, atom, goalgif.

The +TransPred argument specifies the predicate that will perform the transformation. It has to be of arity 2 or 3 and should have the form:
trans_function(OldTerm, NewTerm [, Module]) :- ... .
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.

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:

[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.
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.

A term can be protected against transformation by quoting it with the ``protecting functor'' (by default it is no_macro_expansion/1):  

[eclipse 4]: read(X).
        a(1, no_macro_expansion(a(1, zzz))).
X = b(a(1, zzz)).
Note that the protecting functor is itself defined as a macro:
trprotect(no_macro_expansion(X), X).
:- define_macro(no_macro_expansion/1, trprotect/2, [global, protect_arg]).
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.

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:

[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.
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 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.


next up previous index
Next: Definite Clause Grammars Up: ECLiPSe Macros Previous: Introduction



Micha Meier
Mon Mar 4 12:11:45 MET 1996