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