9. Template definitions

When working with a syntactic representation formalism such as the TIGER language, certain pieces of code will be used over and over again. Furthermore, it is good programming and grammar writing style to define generalizations. Therefore, there is an urgent need for a means for defining abbreviations, templates (cf. [Shieber1986]), or macros. We chose TIGER templates to be non-recursive logical relations. This means that, although template calls may be embedded into template definitions, there must be neither direct nor indirect self-reference in template definitions. Hence, templates realize the 'database programming' part of a logic programming language such as Prolog (cf. [SterlingShapiro1986]).

A simple scheme PrepPhrase of a prepositional phrase which consists only of a preposition (APPR) and a proper noun (NE) can be defined as follows:

PrepPhrase(#n0) <-
   #n0:[cat="PP"] > #n1:[pos="APPR"]
   & #n0 > #n2:[pos="NE"]
   & #n1.#n2
   & arity(#n0,2) ;

The arrow <- marks a defining clause of a template definition. The <- operator is a two-place operator which takes a template head on its lefthand side and a template body on its righthand side. The template head consists of the template name (e.g. PrepPhrase) and a list of variables, the argument parameters of the template clause. The list of argument parameters must have at least one element, because otherwise no information flow between the template body and the calling environment would be possible, i.e. the template definition would be useless. An argument parameter #x must come with enough information (in the template body or in the query context) so that one can decide which of the built-in types Constant, FRec, Node, or Graph, the variable #x belongs to. The template body consists of a graph description. The end of a defining clause is marked by the ; symbol. A template definition can consist of several defining clauses (not yet implemented).

The PrepPhrase template can now be used or called in a query:

#n0 & PrepPhrase(#n0) ;

This query will return all graphs from the given corpus, which contain a subtree (rooted in #n0) with the desired shape.

Please note: The '#n0 &' part is important. TIGERSearch assumes that variables which occur only in the template call but not elsewhere, do not make sense. If you omit the '#n0 &' you will get an error message.

The template PrepPhrase can also be used in the body of some other template definition, e.g. in the definition of a pattern for VerbPhrase like 'geht nach Stuttgart'.

VerbPhrase(#n0) <-
   #n0:[cat="VP"] > #n1:[pos="VVFIN"]
   & #n0 > #n2
   & #n1.#n2
   & arity(#n0,2)
   & PrepPhrase(#n2) ;

Please note: The scope of a variable is the defining clause it occurs in. E.g. the variable #n2 in the definition of PrepPhrase is distinct from the variable #n2 in the definition of VerbPhrase. The TIGER language interpreter will resolve the call to PrepPhrase in the following manner. It will:

  1. look up the defining clause of PrepPhrase.

  2. replace all the variable names by new ones (in order to avoid unintended confusion of variables from the 'calling' clause and the 'called' clause).

  3. identify the node id variable #n2 in VerbPhrase with the argument #n0 of PrepPhrase's defining clause. Identification of variables means that the constraints for both variables are joined into a single constraint by a logical conjunction.

After the resolution step, the VerbPhrase-clause has the following shape:

VerbPhrase(#n0) <-
   #n0:[cat="VP"] > #n1:[pos="VVFIN"]
   & #n0 > #n2
   & #n1.#n2
   & #n2:[cat="PP"] > #n21:[pos="APPR"]
   & #n2 > #n22:[pos="NE"]
   & #n21.#n22
   & arity(#n0,2)
   & arity(#n2,2) ;

If we want to find out which verbs go with which prepositions, this can be done by adding the appropriate arguments or parameters.

PrepPhrase(#n0,#prep) <-
   #n0:[cat="PP"] > #n1:[word=#prep & pos="APPR"]
   & #n0 > #n2:[pos="NE"]
   & #n1.#n2
   & arity(#n0,2) ;

VerbPhrase(#n0,#verblemma,#prep) <-
   #n0:[cat="VP"] > #n1:[pos="VVFIN" & lemma=#verblemma]
   & #n0 > #n2
   & #n1.#n2
   & arity(#n0,2)
   & PrepPhrase(#n2,#prep) ;

After a while, we might get interested in a more complex notion of prepositional phrases. For that reason, a template definition may consist of several, alternative defining clauses (not yet implemented):

PrepPhrase(#n0,#prep) <-
   #n0:[cat="PP"] > #n1:[word=#prep & pos="APPR"]
   & #n0 > #n2:[pos="NE"]
   & #n1.#n2
   & arity(#n0,2) ;

PrepPhrase(#n0,#prep) <-
   #n0:[cat="PP"] > #n1:[word=#prep & pos="APPR"]
   & #n0 > #n2:[pos="ART"]
   & #n0 > #n3:[pos="NN"]
   & #n1.#n2
   & #n2.#n3
   & arity(#n0,3) ;

The above definition is equivalent to a disjunction of the two defining clauses:

PrepPhrase(#n0,#prep) <-
   ( #n0:[cat="PP"] > #n1:[word=#prep & pos="APPR"]
     & #n0 > #n2:[pos="NE"]
     & #n1.#n2
     & arity(#n0,2) )
   |
   ( #n0:[cat="PP"] > #n1:[word=#prep & pos="APPR"]
     & #n0 > #n2:[pos="ART"]
     & #n0 > #n3:[pos="NN"]
     & #n1.#n2
     & #n2.#n3
     & arity(#n0,3) );

or, in a more packed manner:

// packed definition of PrepPhrase
PrepPhrase(#n0,#prep) <-
   #n0:[cat="PP"]
   & #n1:[word=#prep & pos="APPR"]
   & #n1.#n2
   & ( ( #n0 > #n1
         & #n0 > #n2:[pos="NE"]
         & arity(#n0,2) )
       |
       ( #n0 > #n1
         & #n0 > #n2:[pos="ART"]
         & #n0 > #n3:[pos="NN"]
         & #n2.#n3
         & arity(#n0,3) ) ) ;

The //-symbol marks the remainder of a line as a comment.

Types vs. templates

One might think of abbreviating a disjunction of feature values by a template name:

gen-dat(#case) <-
    [ case = #case: ( "gen" | "dat" ) ] ;

But we recommend to use a type definition instead, if possible, since this does not introduce an explicit disjunction into the structure.

gen-dat := "gen", "dat" ;

However, TIGERSearch admits only a single type hierarchy. Therefore, views which are orthogonal to this primary type hierarchy, must be expressed by templates.