[Code]
ALE allows the user to employ a general form of parametric
macros in descriptions. Macros allow the user to define a description
once and then use a shorthand for it in other descriptions. We first
consider a simple example of a macro definition, drawn from the
categorial grammar in the appendix. Suppose the user wants to employ
a description qstore:e_list frequently within a program. The
following macro definition can be used in the program
file:
quantifier_free macro
qstore:e_list.
Then, rather than including the description qstore:e_list in
another description, @ quantifier_free can be used instead.
Whenever @ quantifier_free is used, qstore:e_list is
substituted.
In the above case, the <macro_spec> was a simple atom, but in general, it can be supplied with arguments. The full BNF for macro definitions is as follows:
<macro_def> ::= <macro_head> macro <desc>.
<macro_head> ::= <macro_name>
| <macro_name>(<seq(<var>)>)
<macro_spec> ::= <macro_name>
| <macro_name>(<seq(<desc>)>)
<seq(X)> ::= X
| X, <seq(X)>
Note that <seq(X)> is a parametric category in the BNF
which abbreviates non-empty sequences of objects of category X.
The following clause should be added to recursive definition of
descriptions:
<desc> ::= @ <macro\_spec>A feature structure satisfies a description of the form @ <macrospec> just in case the structure satisfies the body of the definition of the macro.
Again considering the categorial grammar in the appendix, we have the following macros with one and two arguments respectively:
np(Ind) macro
syn:np,
sem:Ind.
n(Restr,Ind) macro
syn:n,
sem:(body:Restr,
ind:Ind).
In general, the arguments in the definition of a macro must be Prolog
variables, which can then be used as variables in the body of the
macro. With the first macro, the description @ np(j) would then
be equivalent to the description syn:np,sem:j. When evaluating
a macro, the argument supplied, in this case j, is substituted
for the variable when expanding the macro. In general, the argument
to a macro can itself be an arbitrary description (possibly containing
macros). For instance, the description:
n((and,conj1:R1,conj2:R2),Ind3)would be equivalent to the description:
syn:n,
sem:(body:(and,conj1:R1,conj2:R2),
ind:Ind3)
This example illustrates how other variables and even complex
descriptions can be substituted for the arguments of macros.
Also note the parentheses around the arguments to the first argument
of the macro. Without the parentheses, as in n(and,conj1:R1,conj2:R2,Ind3), the macro expansion routine would take
this to be a four argument macro, rather than a two argument macro
with a complex first argument. This brings up a related point, which
is that different macros can have the same name as long as they have
the different numbers of arguments.
Macros can also contain other macros, as illustrated by the macro for proper names in the categorial grammar:
pn(Name) macro
synsem: @ np(Name),
@ quantifier_free.
In this case, the macros are expanded recursively, so that the
description pn(j) would be equivalent to the description
synsem:(syn:np,sem:j),qstore:e_list
It is usually a good idea to use macros whenever the same description is going to be re-used frequently. Not only does this make the grammars and programs more readable, it reduces the number of simple typing errors that lead to inconsistencies.
As is to be expected, macros can't be recursive. That is, a macro, when expanded, is not allowed to invoke itself, as in the ill-formed example:
infinite_list(Elt) macro
hd:Elt,
tl:infinite_list(Elt)
The reason is simple; it is not possible to expand this macro to a
finite description. Thus all recursion must occur in grammars or
programs; it can't occur in either the appropriateness conditions or
in macros.
The user should note that variables in the scope of a macro are not the same as ALE feature structure variables -- they denote where macro-substitutions of parameters are made, not instances of re-entrancy in a feature structure. If we employ the following macro:
blah(X) macro
b,
f: X,
g: X.
with the argument (c,h:a) for example we obtain the following
feature structure:
b
F c
H a
G c
H a
where the values of F and G are not shared (unless c
and a are extensional). We can, of course, create a shared
structure using blah, by including an ALE variable in the
actual argument to the macro. Thus blah((Y,c,h:a)) yields:
b
F [0] c
H a
G [0]
Because programming with lists is so common, ALE has a special macro for it, based on the Prolog list notation. A description may also take any of the forms on the left, which will be treated equivalently to the descriptions on the right in the following diagram:
[] e_list
[H|T] (hd:H,
tl:T)
[A1,A2,...,AN] (hd:A1,
tl:(hd:A2,
tl: ...
tl:(hd:AN,
tl:e_list)...))
[A1,...,AN|T] (hd:A1,
tl:(hd:A2,
tl: ...
tl:(hd:AN,
tl:T)...))
Note that this built-in macro does not require the macro operator @. Thus, for example, the description [a|T3] is equivalent to
hd:a,tl:T3, and the description [a,b,c] is equivalent to
hd:a,tl:(hd:b,tl:(hd:c,tl:e_list)). There are many example of
this use of Prolog's list notation in the grammars in the appendix.