3045 lines
125 KiB
Plaintext
3045 lines
125 KiB
Plaintext
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Research Report AI-1989-01
|
|||
|
Artificial Intelligence Programs
|
|||
|
The University of Georgia
|
|||
|
Athens, Georgia 30602
|
|||
|
|
|||
|
Available by ftp from
|
|||
|
aisun1.ai.uga.edu
|
|||
|
(128.192.12.9)
|
|||
|
|
|||
|
Series editor:
|
|||
|
Michael Covington
|
|||
|
mcovingt@aisun1.ai.uga.edu
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
GULP 2.0: An Extension of
|
|||
|
Prolog for Unification-Based Grammar
|
|||
|
|
|||
|
Michael A. Covington
|
|||
|
|
|||
|
Advanced Computational Methods Center
|
|||
|
University of Georgia
|
|||
|
Athens, Georgia 30602
|
|||
|
|
|||
|
January 1989
|
|||
|
|
|||
|
ABSTRACT: A simple extension to Prolog facilitates
|
|||
|
implementation of unification-based grammars (UBGs) by
|
|||
|
adding a new notational device, the feature structure,
|
|||
|
whose behavior emulates graph unification. For
|
|||
|
example, a:b..c:d denotes a feature structure in
|
|||
|
which a has the value b, c has the value d, and the
|
|||
|
values of all other features are unspecified. A
|
|||
|
modified Prolog interpreter translates feature
|
|||
|
structures into Prolog terms that unify in the desired
|
|||
|
way. Thus, the extension is purely syntactic,
|
|||
|
analogous to the automatic translation of "abc" to
|
|||
|
[97,98,99] in Edinburgh Prolog.
|
|||
|
The extended language is known as GULP (Graph
|
|||
|
Unification Logic Programming); it is as powerful and
|
|||
|
concise as PATR-II (Shieber 1986a,b) and other grammar
|
|||
|
development tools, while retaining all the versatility
|
|||
|
of Prolog. GULP can be used with grammar rule notation
|
|||
|
(DCGs) or any other parser that the programmer cares
|
|||
|
to implement.
|
|||
|
Besides its uses in natural language processing,
|
|||
|
GULP provides a way to supply keyword arguments to any
|
|||
|
procedure.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
1. Introduction
|
|||
|
|
|||
|
A number of software tools have been developed for
|
|||
|
implementing unification-based grammars, among them PATR-II
|
|||
|
(Shieber 1986a,b), D-PATR (Karttunen 1986a), PrAtt (Johnson and
|
|||
|
Klein 1986), and AVAG (Sedogbo 1986). This paper describes a
|
|||
|
simple extension to the syntax of Prolog that serves the same
|
|||
|
purpose while making a much less radical change to the language.
|
|||
|
Unlike PATR-II and similar systems, this system treats feature
|
|||
|
structures as first-class objects that appear in any context, not
|
|||
|
just in equations.1 Further, feature structures can be used not
|
|||
|
|
|||
|
|
|||
|
1 The first version of GULP (Covington 1987) was
|
|||
|
developed with support from National Science Foundation
|
|||
|
Grant IST-85-02477. I want to thank Franz Guenthner,
|
|||
|
Rainer B<>uerle, and the other researchers at the
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
2
|
|||
|
|
|||
|
only in natural language processing, but also to pass keyword
|
|||
|
arguments to any procedure.
|
|||
|
|
|||
|
The extension is known as GULP (Graph Unification Logic
|
|||
|
Programming). It allows the programmer to write a:b..c:d to
|
|||
|
stand for a feature structure in which feature a has the value b,
|
|||
|
feature c has the value d, and all other features are
|
|||
|
uninstantiated.2 The interpreter translates feature structures
|
|||
|
written in this notation into ordinary Prolog terms that unify in
|
|||
|
the desired way. Thus, this extension is similar in spirit to
|
|||
|
syntactic devices already in the language, such as writing "abc"
|
|||
|
for [97,98,99] or writing [a,b,c] for .(a,.(b,.(c,nil))).
|
|||
|
|
|||
|
GULP can be used with grammar rule notation (definite clause
|
|||
|
grammars, DCGs) or with any parser that the programmer cares to
|
|||
|
implement in Prolog.
|
|||
|
|
|||
|
|
|||
|
2. What is unification-based grammar?
|
|||
|
|
|||
|
2.1. Unification-based theories
|
|||
|
|
|||
|
Unification-based grammar (UBG) comprises all theories of
|
|||
|
grammar in which unification (merging) of feature structures plays
|
|||
|
a prominent role. As such, UBG is not a theory of grammar but
|
|||
|
rather a formalism in which theories of grammar can be expressed.
|
|||
|
Such theories include functional unification grammar, lexical-
|
|||
|
functional grammar (Kaplan and Bresnan 1982), generalized phrase
|
|||
|
structure grammar (Gazdar et al. 1986), head-driven phrase
|
|||
|
structure grammar (Pollard and Sag 1987), and others.
|
|||
|
|
|||
|
UBGs use context-free grammar rules in which the nonterminal
|
|||
|
symbols are accompanied by sets of features. The addition of
|
|||
|
features increases the power of the grammar so that it is no
|
|||
|
longer context-free; indeed, in the worst case, parsing with such
|
|||
|
a grammar can be NP-complete (Barton, Berwick, and Ristad 1987:93-
|
|||
|
96).
|
|||
|
|
|||
|
However, in practice, these intractable cases are rare.
|
|||
|
Theorists restrain their use of features so that the grammars, if
|
|||
|
not actually context-free, are close to it, and context-free
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Seminar f<>r nat<61>rlich-sprachliche Systeme, University
|
|||
|
of T<>bingen, for their hospitality and for helpful
|
|||
|
discussions. The opinions and conclusions expressed
|
|||
|
here are solely those of the author.
|
|||
|
|
|||
|
2 This use of the colon makes the Quintus Prolog
|
|||
|
and Arity Prolog module systems unavailable; so far,
|
|||
|
this has not caused problems.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
3
|
|||
|
|
|||
|
parsing techniques are successful and efficient. Joshi (1986) has
|
|||
|
described this class of grammars as "mildly context-sensitive."
|
|||
|
|
|||
|
|
|||
|
2.2. Grammatical features
|
|||
|
|
|||
|
Grammarians have observed since ancient times that each word
|
|||
|
in a sentence has a set of attributes, or features, that determine
|
|||
|
its function and restrict its usage. Thus:
|
|||
|
|
|||
|
|
|||
|
The dog barks.
|
|||
|
|
|||
|
category:determiner category:noun category:verb
|
|||
|
number:singular number:singular
|
|||
|
person:3rd
|
|||
|
tense:present
|
|||
|
|
|||
|
|
|||
|
|
|||
|
The earliest generative grammars of Chomsky (1957) and others
|
|||
|
ignored all of these features except category, generating
|
|||
|
sentences with context-free phrase-structure rules such as
|
|||
|
|
|||
|
sentence --> noun phrase + verb phrase
|
|||
|
|
|||
|
noun phrase --> determiner + noun
|
|||
|
|
|||
|
plus transformational rules that rearranged syntactic structure.
|
|||
|
Syntactic structure was described by tree diagrams (Figure 1).3
|
|||
|
Number and tense markers were treated as separate elements of the
|
|||
|
string (e.g., boys = boy + s). "Subcategorization" distinctions,
|
|||
|
such as the fact that some verbs take objects and other verbs do
|
|||
|
not, were handled by splitting a single category, such as verb,
|
|||
|
into two (verbtransitive and verbintransitive).
|
|||
|
|
|||
|
But complex, cross-cutting combinations of features cannot
|
|||
|
be handled in this way, and Chomsky (1965) eventually attached
|
|||
|
feature bundles to all the nodes in the tree (Figure 2). His
|
|||
|
contemporaries accounted for grammatical agreement (e.g., the
|
|||
|
agreement of the number features of subject and verb) by means of
|
|||
|
transformations that copied features from one node to another.
|
|||
|
This remained the standard account of grammatical agreement for
|
|||
|
many years.
|
|||
|
|
|||
|
But feature copying is unnecessarily procedural. It
|
|||
|
presumes, unjustifiably, that whenever two nodes agree, one of
|
|||
|
them is the source and the other is the destination of a copied
|
|||
|
feature. In practice, the source and destination are hard to
|
|||
|
|
|||
|
|
|||
|
3 Figures are printed at the end of this document.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
4
|
|||
|
|
|||
|
distinguish. Do singular subjects require singular verbs, or do
|
|||
|
singular verbs require singular subjects? This is an empirically
|
|||
|
meaningless question. Moreover, when agreement processes interact
|
|||
|
to combine features from a number of nodes, the need to
|
|||
|
distinguish source from destination introduces unnecessary
|
|||
|
clumsiness.
|
|||
|
|
|||
|
|
|||
|
2.3. Unification-based grammar
|
|||
|
|
|||
|
Unification-based grammar attacks the same problem non-
|
|||
|
procedurally, by stating constraints on feature values. For
|
|||
|
example, the rule
|
|||
|
|
|||
|
[2.3a] PP --> P NP
|
|||
|
[case:acc]
|
|||
|
|
|||
|
says that in a prepositional phrase, the NP must be in the
|
|||
|
accusative case.
|
|||
|
|
|||
|
More precisely, rule [2.3a] says the feature structure
|
|||
|
|
|||
|
[case:acc]
|
|||
|
|
|||
|
must be unified (merged) with whatever features the NP already
|
|||
|
has. If the NP already has case:acc, all is well. If the NP has
|
|||
|
no value for case, it acquires case:acc. But if the NP has
|
|||
|
case with some value other than acc, the unification fails and
|
|||
|
the rule cannot apply.
|
|||
|
|
|||
|
Agreement is handled with variables, as in the rule
|
|||
|
|
|||
|
|
|||
|
[2.3b] S --> NP VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> person:X <20> <20> person:X <20>
|
|||
|
<20> number:Y <20> <20> number:Y <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
which requires the NP and VP to agree in person and number. Here
|
|||
|
X and Y are variables; person:X merges with the person
|
|||
|
feature of both the NP and the VP, thereby ensuring that the same
|
|||
|
value is present in both places. The same thing happens with
|
|||
|
number.
|
|||
|
|
|||
|
Strictly speaking, the category label (S, NP, VP, etc.) is
|
|||
|
part of the feature structure. Thus,
|
|||
|
|
|||
|
NP
|
|||
|
[case:acc]
|
|||
|
|
|||
|
is short for:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
5
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> category:NP <20>
|
|||
|
<20> case:acc <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
In practice, however, the category label usually plays a primary
|
|||
|
role in parsing, and it is convenient to give it a special status.
|
|||
|
|
|||
|
Grammar rules can alternatively be written in terms of
|
|||
|
equations that the feature values must satisfy. In equational
|
|||
|
notation, rules [2.3a] and [2.3b] become:
|
|||
|
|
|||
|
[2.3c] PP --> P NP NP case = acc
|
|||
|
|
|||
|
[2.3d] S --> NP VP NP person = VP person
|
|||
|
NP number = VP number
|
|||
|
|
|||
|
or even, if the category label is to be treated as a feature,
|
|||
|
|
|||
|
[2.3e] X --> Y Z X category = PP
|
|||
|
Y category = P
|
|||
|
Z category = NP
|
|||
|
Z case = acc
|
|||
|
|
|||
|
[2.3f] X --> Y Z X category = S
|
|||
|
Y category = NP
|
|||
|
Z category = VP
|
|||
|
Y person = Z person
|
|||
|
Y number = Z number
|
|||
|
|
|||
|
where X, Y, and Z are variables. Equations are used in PATR-II,
|
|||
|
PrAtt, and other implementation tools, but not in the system
|
|||
|
described here.
|
|||
|
|
|||
|
The value of a feature can itself be a feature structure.
|
|||
|
This makes it possible to group features together to express
|
|||
|
generalizations. For instance, one can group syntactic and
|
|||
|
semantic features together, creating structures such as:
|
|||
|
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> syn:<3A> case:acc <20> <20>
|
|||
|
<20> <20> gender:masc <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:MAN <20> <20>
|
|||
|
<20> <20> countable:yes <20> <20>
|
|||
|
<20> <20> animate:yes <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
Then a rule can copy the syntactic or semantic features en masse
|
|||
|
to another node, without enumerating them.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
6
|
|||
|
|
|||
|
2.4. A sample grammar
|
|||
|
|
|||
|
Features provide a powerful way to pass information from one
|
|||
|
place to another in a grammatical description. The grammar in
|
|||
|
Figure 3 is an example. It uses features not only to ensure the
|
|||
|
grammaticality of the sentences generated, but also to build a
|
|||
|
representation of the meaning of the sentence. Every constituent
|
|||
|
has a sem feature representing its meaning. The rules combine the
|
|||
|
meanings of the individual words into predicate-argument
|
|||
|
structures representing the meanings of all of the constituents.
|
|||
|
The meaning of the sentence is represented by the sem feature of
|
|||
|
the topmost S node.
|
|||
|
|
|||
|
Like all the examples given here, this grammar is intended
|
|||
|
only as a demonstration of the power of unification-based grammar,
|
|||
|
not as a viable linguistic analysis. Thus, for simplicity, the
|
|||
|
internal structure of the NP is ignored and the proposal to group
|
|||
|
syntactic features together is abandoned.
|
|||
|
|
|||
|
To see how the grammar works, consider how the sentence Max
|
|||
|
sees Bill would be parsed bottom-up. The process is shown in
|
|||
|
Figure 4. First rules [c], [d], and [e] supply the features of the
|
|||
|
individual words (Figure 4a). Next the bottom-up parser attempts
|
|||
|
to build constituents.
|
|||
|
|
|||
|
By rule [b], sees and Bill constitute a VP (Figure 4b). At
|
|||
|
this step, construction of a semantic representation begins. The
|
|||
|
sem feature of the VP has as its value another feature structure
|
|||
|
which contains two features: pred, the semantics of the verb, and
|
|||
|
arg2, the semantics of the direct object.
|
|||
|
|
|||
|
Rule [b] also assigns the feature case:acc to Bill; this
|
|||
|
has no effect on the form of the noun but would be important if a
|
|||
|
pronoun had been used instead.
|
|||
|
|
|||
|
Finally, rule [a] allows the resulting NP and VP to be
|
|||
|
grouped together into an S (Figure 4c). This rule assigns
|
|||
|
nominative case to Max and combines the semantics of the NP and VP
|
|||
|
to construct the sem feature of the S node, thereby accounting
|
|||
|
for the meaning of the complete sentence.
|
|||
|
|
|||
|
It would be equally feasible to parse top-down. Parsing
|
|||
|
would then begin with an S node, expanded to NP and VP by rule
|
|||
|
[a]. The NP would then expand to Max using rule [d], thereby
|
|||
|
supplying a value for sem of NP, and hence also for sem:arg1 of
|
|||
|
S. Similarly, expansion of the VP would supply values for the
|
|||
|
remaining features of S.
|
|||
|
|
|||
|
Crucially, it is possible (and necessary) to match variables
|
|||
|
with each other before giving them values. In a top-down parse, we
|
|||
|
know that sem:arg2 of S will have the same value as sem:arg2
|
|||
|
of VP long before we know what this value is to be.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
7
|
|||
|
|
|||
|
|
|||
|
2.5. Functions, paths, re-entrancy, and graphs
|
|||
|
|
|||
|
A feature can be viewed as a partial function which, given a
|
|||
|
feature structure, may or may not yield a value. For instance,
|
|||
|
given the structure
|
|||
|
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> syn:<3A> case:acc <20> <20>
|
|||
|
<20> <20> gender:masc <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem: MAN <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
the feature sem yields the value MAN, the feature syn yields
|
|||
|
another feature structure, and the feature tense yields no value
|
|||
|
(it is a case in which the partial function is undefined).
|
|||
|
|
|||
|
A path is a series of features that pick out an element of a
|
|||
|
nested feature structure. Formally, a path is the composition of
|
|||
|
the functions just mentioned. For example, the path syn:case is
|
|||
|
what you get by applying the function case to the value of the
|
|||
|
function syn; applied to the structure above, syn:case yields
|
|||
|
the value acc. Path notation provides a way to refer to a single
|
|||
|
feature deep in a nested structure without writing nested
|
|||
|
brackets. Thus one can write rules such as
|
|||
|
|
|||
|
P --> P NP
|
|||
|
[syn:case:acc]
|
|||
|
|
|||
|
|
|||
|
or, in equational form,
|
|||
|
|
|||
|
P --> P NP NP syn case = acc
|
|||
|
|
|||
|
Feature structures are re-entrant. This means that features
|
|||
|
are like pointers; if two of them have the same value, then they
|
|||
|
point to the same object, not to two similar objects. If this
|
|||
|
object is subsequently modified (e.g., by giving values to
|
|||
|
variables), the change will show up in both places. Thus the
|
|||
|
structure
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> c:b <20>
|
|||
|
<20> e:d <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
is more accurately represented as something like:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
8
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a <20><><EFBFBD><EFBFBD><EFBFBD> b <20>
|
|||
|
<20> c <20><><EFBFBD> <20>
|
|||
|
<20> e <20><><EFBFBD><EFBFBD><EFBFBD> d <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
There is only one b, and a and c both point to it.
|
|||
|
|
|||
|
Re-entrant feature structures can be formelized as directed
|
|||
|
acyclic graphs (DAGs) as shown in Figure 5. Features are arcs and
|
|||
|
feature values are the vertices or subgraphs found at the ends of
|
|||
|
the arcs. A path is a series of arcs chained together.
|
|||
|
|
|||
|
Re-entrancy follows from the way variables behave in a
|
|||
|
grammar. All occurrences of the same variable take on the same
|
|||
|
value at the same time. (As in Prolog, like-named variables in
|
|||
|
separate rules are not considered to be the same variable.) The
|
|||
|
value may itself contain a variable that will later get a value
|
|||
|
from somewhere else. This is why bottom-up and top-down parsing
|
|||
|
work equally well.
|
|||
|
|
|||
|
|
|||
|
2.6. Unification
|
|||
|
|
|||
|
Our sample grammar relies on the merging of partially
|
|||
|
specified feature structures. Thus, the subject of the sentence
|
|||
|
gets case from rule [a] and semantics from rule [d] or [e]. This
|
|||
|
merging can be formalized as unification. The unifier of two
|
|||
|
feature structures A and B is the smallest feature structure C
|
|||
|
that contains all the information in both A and B.
|
|||
|
|
|||
|
Feature structure unification is equivalent to graph
|
|||
|
unification, i.e., merging of directed acyclic graphs, as defined
|
|||
|
in graph theory. The unifier of two graphs is the smallest graph
|
|||
|
that contains all the nodes and arcs in the graphs being unified.
|
|||
|
This is similar but not identical to Prolog term unification;
|
|||
|
crucially, elements of the structure are identified only by name,
|
|||
|
not (as in Prolog) by position.
|
|||
|
|
|||
|
Formally, the unification of feature structures A and B
|
|||
|
(giving C) is defined as follows:
|
|||
|
|
|||
|
(1) Any feature that occurs in A but not B, or in B but not
|
|||
|
A, also occurs in C with the same value.
|
|||
|
|
|||
|
(2) Any feature that occurs in both A and B also occurs in
|
|||
|
C, and its value in C is the unifier of its values in A and
|
|||
|
B.
|
|||
|
|
|||
|
Feature values, in turn, are unified as follows:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
9
|
|||
|
|
|||
|
(a) If both values are atomic symbols, they must be the same
|
|||
|
atomic symbol, or else the unification fails (the unifier
|
|||
|
does not exist).
|
|||
|
|
|||
|
(b) A variable unifies with any object by becoming that
|
|||
|
object. All occurrences of that variable henceforth
|
|||
|
represent the object with which the variable has unified.
|
|||
|
Two variables can unify with each other, in which case they
|
|||
|
become the same variable.
|
|||
|
|
|||
|
(c) If both values are feature structures, they unify by
|
|||
|
applying this process recursively.
|
|||
|
|
|||
|
Thus
|
|||
|
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> a:b <20> and <20> c:d <20>
|
|||
|
<20> c:d <20> <20> e:f <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
|
|||
|
unify giving:
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> c:d <20>
|
|||
|
<20> e:f <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
Likewise, [a:X] and [a:b] unify, instantiating X to the value
|
|||
|
b; and
|
|||
|
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> a:X <20> and <20> a:c <20>
|
|||
|
<20> b:c <20> <20> b:Y <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
unify by instantiating both X and Y to c.
|
|||
|
|
|||
|
As in Prolog, unification is not always possible.
|
|||
|
Specifically, if A and B have different (non-unifiable) values for
|
|||
|
some feature, unification fails. A grammar rule requiring A to
|
|||
|
unify with B cannot apply if A and B are not unifiable.
|
|||
|
|
|||
|
Unification-based grammars rely on failure of unification to
|
|||
|
rule out ungrammatical sentences. Consider, for example, why our
|
|||
|
sample grammar generates Max sees me but not Me sees Max. In Max
|
|||
|
sees me, both rule [b] and rule [f] specify that me has the
|
|||
|
feature case:acc, giving the structure shown in Figure 6.
|
|||
|
|
|||
|
However, in Me sees Max, the case of me raises a conflict.
|
|||
|
Rule [a] specifies case:nom and rule [f] specifies case:acc.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
10
|
|||
|
|
|||
|
These values are not unifiable; hence the specified merging of
|
|||
|
feature structures cannot go through, and the sentence is not
|
|||
|
generated by the grammar.
|
|||
|
|
|||
|
|
|||
|
2.7. Declarativeness
|
|||
|
|
|||
|
Unification-based grammars are declarative, not procedural.
|
|||
|
That is, they are statements of well-formedness conditions, not
|
|||
|
procedures for generating or parsing sentences. That is why, for
|
|||
|
example, sentences generated by our sample grammar can be parsed
|
|||
|
either bottom-up or top-down.
|
|||
|
|
|||
|
This declarativeness comes from the fact that unification is
|
|||
|
an order-independent operation. The unifier of A, B, and C is the
|
|||
|
same regardless of the order in which the three structures are
|
|||
|
combined. This is true of both graph unification and Prolog term
|
|||
|
unification.
|
|||
|
|
|||
|
The declarative nature of UBGs is subject to two caveats.
|
|||
|
First, although unification is order-independent, particular
|
|||
|
parsing algorithms are not. Recall that grammar rules of the form
|
|||
|
|
|||
|
A --> A B
|
|||
|
|
|||
|
cannot be parsed top-down, because they lead to infinite loops
|
|||
|
("To parse an A, parse an A and then..."). Now consider a rule of
|
|||
|
the form
|
|||
|
|
|||
|
A --> A B
|
|||
|
[f:X] [f:Y]
|
|||
|
|
|||
|
If X and Y have different values, then top-down parsing works
|
|||
|
fine; if either X or Y does not have a value at the time the rule
|
|||
|
is invoked, top-down parsing will lead to a loop. This shows that
|
|||
|
one cannot simply give an arbitrary UBG to an arbitrary parser and
|
|||
|
expectuseful results;the order ofinstantiation mustbe keptin mind.
|
|||
|
|
|||
|
Second, many common Prolog operations are not order-
|
|||
|
independent, and this must be recognized in any implementation
|
|||
|
that allows Prolog goals to be inserted into grammar rules.
|
|||
|
Obviously, the cut (!) interferes with order-independence by
|
|||
|
blocking alternatives that would otherwise succeed. More
|
|||
|
commonplace predicates such as write, is, and == lack order-
|
|||
|
independence because they behave differently depending on whether
|
|||
|
their arguments are instantiated at the time of execution.
|
|||
|
Colmerauer's Prolog II (Giannesini et al. 1986) avoids some of
|
|||
|
these difficulties by allowing the programmer to postpone tests
|
|||
|
until a variable becomes instantiated, whenever that may be.
|
|||
|
|
|||
|
|
|||
|
2.8. Building structures and moving data
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
11
|
|||
|
|
|||
|
Declarative unification-based rules do more than just pass
|
|||
|
information up and down the tree. They can build structure as they
|
|||
|
go. For example, the rule
|
|||
|
|
|||
|
|
|||
|
VP --> V NP
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:X <20> <20> <20> sem:X <20> <20> sem:Y <20>
|
|||
|
<20> <20> arg:Y <20> <20> <20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
builds on the VP node a pred-arg structure that is absent on the V
|
|||
|
and NP.
|
|||
|
|
|||
|
Unification can pass information around in directions other
|
|||
|
than along the lines of the tree diagram. This is done by
|
|||
|
splitting a feature into two sub-features, one for input and the
|
|||
|
other for output. The inputs and outputs can then be strung
|
|||
|
together in any manner.
|
|||
|
|
|||
|
Consider for example the rule:
|
|||
|
|
|||
|
S --> NP VP
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:<3A> in:X1 <20> <20> <20> sem:<3A> in:X1 <20> <20> <20> sem:<3A> in:X2 <20> <20>
|
|||
|
<20> <20> out:X3 <20> <20> <20> <20> out:X2 <20> <20> <20> <20> out:X3 <20> <20>
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
|
|||
|
This rule assumes that sem of the S has some initial value
|
|||
|
(perhaps an empty list) which is passed into X1 from outside. X1
|
|||
|
is then passed to the NP, which modifies it in some way, giving
|
|||
|
X2, which is passed to the VP for further modification. The
|
|||
|
output of the VP is X3, which becomes the output of the S.
|
|||
|
|
|||
|
Such a rule is still declarative and can work either forward
|
|||
|
or backward; that is, parsing can still take place top-down or
|
|||
|
bottom-up. Further, any node in the tree can communicate with any
|
|||
|
other node via a string of input and output features, some of
|
|||
|
which simply pass information along unchanged. The example in
|
|||
|
section 4.2 below uses input and output features to undo unbounded
|
|||
|
movements of words. Johnson and Klein (1985, 1986) use in and out
|
|||
|
features to perform complex manipulations of semantic structure;
|
|||
|
see section 4.3 (below) for a GULP reconstruction of part of one
|
|||
|
of their programs.
|
|||
|
|
|||
|
|
|||
|
3. The GULP translator
|
|||
|
|
|||
|
3.1. Feature structures in GULP
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
12
|
|||
|
|
|||
|
The key idea of GULP is that feature structures can be
|
|||
|
included in Prolog programs as ordinary data items. For instance,
|
|||
|
the feature structure
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> c:d <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
is written:
|
|||
|
|
|||
|
a:b..c:d
|
|||
|
|
|||
|
and GULP translates a:b..c:d into an internal representation
|
|||
|
(called a value list) in which the a position is occupied by b,
|
|||
|
the c position is occupied by d, and all other positions, if any,
|
|||
|
are uninstantiated.
|
|||
|
|
|||
|
This is analogous to the way ordinary Prolog translates
|
|||
|
strings such as "abc" into lists of ASCII codes. The GULP
|
|||
|
programmer always uses feature structure notation and never deals
|
|||
|
directly with value lists. Feature structures are order-
|
|||
|
independent; the translations of a:b..c:d and of c:d..a:b are
|
|||
|
the same.
|
|||
|
|
|||
|
Nesting and paths are permitted. Thus, the structure
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> c:<3A> d:e <20> <20>
|
|||
|
<20> <20> f:g <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
is written a:b..c:(d:e..f:g).4 The same structure can be
|
|||
|
written as
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> c:d:e <20>
|
|||
|
<20> c:f:g <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
which GULP renders as a:b..c:d:e..c:f:g.
|
|||
|
|
|||
|
GULP feature structures are data items -- complex terms --
|
|||
|
not statements or operations. They are most commonly used as
|
|||
|
arguments. Thus, the rule
|
|||
|
|
|||
|
|
|||
|
4 Arity Prolog 4.0 requires a space before the
|
|||
|
'('.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
13
|
|||
|
|
|||
|
S --> NP VP
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
<20> person:X <20> <20> person:X <20> <20> person:X <20>
|
|||
|
<20> number:Y <20> <20> number:Y <20> <20> number:Y <20>
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
|
|||
|
can be written in DCG notation, using GULP, as:
|
|||
|
|
|||
|
s(person:X..number:Y) -->
|
|||
|
np(person:X..number:Y),
|
|||
|
vp(person:X..number:Y).
|
|||
|
|
|||
|
They can also be processed by ordinary Prolog predicates. For
|
|||
|
example, the predicate
|
|||
|
|
|||
|
nonplural(number:X) :- nonvar(X), X \= plural.
|
|||
|
|
|||
|
succeeds if and only if its argument is a feature structure whose
|
|||
|
number feature is instantiated to some value other than plural.
|
|||
|
|
|||
|
Any feature structure unifies with any other feature
|
|||
|
structure unless prevented by conflicting values. Thus, the
|
|||
|
internal representations of a:b..c:d and c:d..e:f unify,
|
|||
|
giving a:b..c:d..e:f. But a:b does not unify with a:d because
|
|||
|
b and d do not unify with each other.
|
|||
|
|
|||
|
|
|||
|
3.2. GULP syntax
|
|||
|
|
|||
|
Formally, GULP adds to Prolog the operators `:' and `..'
|
|||
|
and a wide range of built-in predicates. The operator `:' joins a
|
|||
|
feature to its value, which itself can be another feature
|
|||
|
structure. Thus in c:d:e, the value of c is d:e.
|
|||
|
|
|||
|
A feature-value pair is the simplest kind of feature
|
|||
|
structure. The operator `..' combines feature-value pairs to
|
|||
|
build more complex feature structures.5 This is done by simply
|
|||
|
unifying them. For example, the internal representation of
|
|||
|
a:b..c:d is built by unifying the internal representations of
|
|||
|
a:b and c:d.
|
|||
|
|
|||
|
This fact can be exploited to write "improperly nested"
|
|||
|
feature structures. For example,
|
|||
|
|
|||
|
a:b..c:X..c:d:Y..Z
|
|||
|
|
|||
|
denotes a feature structure in which:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
5 For compatibility with earlier versions, `..'
|
|||
|
can also be written `::'.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
14
|
|||
|
|
|||
|
the value of a is b,
|
|||
|
|
|||
|
the value of c unifies with X,
|
|||
|
|
|||
|
the value of c also unifies with d:Y, and
|
|||
|
|
|||
|
the whole structure unifies with Z.
|
|||
|
|
|||
|
Both operators, `:' and `..', are right-associative; that
|
|||
|
is, a:b:c = a:(b:c) and A..B..C = A..(B..C). Arity
|
|||
|
Prolog 4.0 requires an intervening space when `:' or `..' occurs
|
|||
|
adjacent to a left parenthesis; other Prologs lack this
|
|||
|
restriction.
|
|||
|
|
|||
|
|
|||
|
3.3. Built-in predicates
|
|||
|
|
|||
|
GULP 2.0 is an ordinary Prolog environment with some built-
|
|||
|
in predicates added. The most important of these is load, which
|
|||
|
loads clauses into memory through the GULP translator. (A
|
|||
|
consult or reconsult would not translate feature structures
|
|||
|
into their internal representations.) Thus,
|
|||
|
|
|||
|
?- load myprog.
|
|||
|
|
|||
|
loads clauses from the file MYPROG.GLP.
|
|||
|
|
|||
|
Like reconsult, load clears away any pre-existing clauses
|
|||
|
for a predicate when new clauses for that predicate (with the same
|
|||
|
arity) are first encountered in a file. However, load does not
|
|||
|
require the clauses for a predicate to be contiguous, so long as
|
|||
|
they all occur in the same file. A program can consist of several
|
|||
|
files that are loaded into memory together.
|
|||
|
|
|||
|
Another predicate, ed, calls a full-screen editor and then
|
|||
|
loads the file. Without an argument, ed or load uses the same
|
|||
|
file name as on the most recent invocation of either ed or load.
|
|||
|
|
|||
|
Other special predicates are used within the program. GULP
|
|||
|
1.1 required a declaration such as
|
|||
|
|
|||
|
g_features([gender,number,case,person,tense]).
|
|||
|
|
|||
|
declaring all feature names before any were used. This declaration
|
|||
|
is optional in GULP 2.0. If present, it establishes the order in
|
|||
|
which features will appear whenever a feature structure is output,
|
|||
|
and it can be used to optimize the program by putting frequently
|
|||
|
used features at the beginning. Further, whether or not the
|
|||
|
programmer includes a g_features declaration, GULP 2.0 maintains
|
|||
|
in memory an up-to-date g_features clause with a list of all the
|
|||
|
features actually used, in the order in which they were
|
|||
|
encountered.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
15
|
|||
|
|
|||
|
The predicate g_translate/2 interconverts feature
|
|||
|
structures and their internal representations. This makes it
|
|||
|
possible to process, at runtime, feature structures in GULP
|
|||
|
notation rather than translated form. For instance, if X is a
|
|||
|
feature structure, then g_translate(Y,X), write(Y) will
|
|||
|
display it in GULP notation.
|
|||
|
|
|||
|
The predicate display_feature_structure outputs a
|
|||
|
feature structure, not in GULP notation, but in a convenient
|
|||
|
tabular format, thus:
|
|||
|
|
|||
|
syn: case: acc
|
|||
|
gender: masc
|
|||
|
sem: pred: MAN
|
|||
|
countable: yes
|
|||
|
animate: yes
|
|||
|
|
|||
|
This is similar to traditional feature structure notation, but
|
|||
|
without brackets.
|
|||
|
|
|||
|
|
|||
|
3.4. Internal representation
|
|||
|
|
|||
|
The nature of value lists, which represent feature
|
|||
|
structures internally, is best approached by a series of
|
|||
|
approximations. The nearest Prolog equivalent to a feature
|
|||
|
structure is a complex term with one position reserved for the
|
|||
|
value of every feature. Thus
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> number:plural <20>
|
|||
|
<20> person:third <20>
|
|||
|
<20> gender:fem <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
could be represented as x(plural,third,fem) or
|
|||
|
[plural,third,fem] or the like. It is necessary to decide in
|
|||
|
advance which argument position corresponds to each feature.
|
|||
|
|
|||
|
A feature structure that does not use all of the available
|
|||
|
features is equivalent to a term with anonymous variables; thus
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> person:third <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
would be represented as x(_,third,_) or [_,third,_].
|
|||
|
|
|||
|
Structures of this type simulate graph unification in the
|
|||
|
desired way. They can be recursively embedded. Further,
|
|||
|
structures built by instantiating Prolog variables are inherently
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
16
|
|||
|
|
|||
|
re-entrant, since an instantiated Prolog variable is actually a
|
|||
|
pointer to the memory representation of its value.
|
|||
|
|
|||
|
All the feature structures in a program must be unifiable
|
|||
|
unless they contain conflicting values. Accordingly, if fifteen
|
|||
|
features are used in the program, every value list must reserve
|
|||
|
positions for all fifteen. One option would be to represent value
|
|||
|
lists as 15-argument structures:
|
|||
|
|
|||
|
tense:present => x(_,_,_,_,present,_,_,_,_,_,_,_,_,_,_)
|
|||
|
|
|||
|
This obviously wastes memory. A better solution would be to
|
|||
|
use lists; a list with an uninstantiated tail unifies with any
|
|||
|
longer list. The improved representation is:
|
|||
|
|
|||
|
tense:present => [_,_,_,_,present|_]
|
|||
|
|
|||
|
By putting frequently used features near the beginning, this
|
|||
|
representation can save a considerable amount of memory as well as
|
|||
|
reducing the time needed to do unifications. Further, lists with
|
|||
|
uninstantiated tails gain length automatically as further elements
|
|||
|
are filled in; unifying [a,b,c|_] with [_,_,_,_,e|_] gives
|
|||
|
[a,b,c,_,e|_].
|
|||
|
|
|||
|
If most of the lists in the program have uninstantiated
|
|||
|
tails, the program can be simplified by requiring all lists to
|
|||
|
have uninstantiated tails. Any process that searches through a
|
|||
|
list will then need to check for only one terminating condition
|
|||
|
(remainder of list uninstantiated) rather than two (remainder of
|
|||
|
list uninstantiated or empty).
|
|||
|
|
|||
|
But the GULP internal value list structure is not an
|
|||
|
ordinary list. If it were, translated feature structures would be
|
|||
|
confused with ordinary Prolog lists, and programmers would fall
|
|||
|
victim to unforeseen unifications. It would also be impossible to
|
|||
|
test whether a term is a value list.
|
|||
|
|
|||
|
Recall that Prolog lists are held together by the functor
|
|||
|
`.'. That is,
|
|||
|
|
|||
|
[a,b,c|X] = .(a,.(b,.(c,X)))
|
|||
|
|
|||
|
To get a distinct type of list, all we need to do is substitute
|
|||
|
another functor for the dot. GULP uses g_/2. (In fact, all
|
|||
|
functors beginning with g_ are reserved by GULP for internal
|
|||
|
use.) So if tense is the fifth feature in the canonical order,
|
|||
|
then
|
|||
|
|
|||
|
tense:present => g_(_,g_(_,g_(_,g_(_,g_(present,_)))))
|
|||
|
|
|||
|
It doesn't matter that this looks ugly; the GULP programmer never
|
|||
|
sees it.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
17
|
|||
|
|
|||
|
One more refinement (absent before GULP version 2.0) is
|
|||
|
needed. We want to be able to translate value lists back into
|
|||
|
feature structure notation. For this purpose we must distinguish
|
|||
|
features that are unmentioned from features that are merely
|
|||
|
uninstantiated. That is, we do not want tense:X to turn into an
|
|||
|
empty feature structure just because X is uninstantiated. It may
|
|||
|
be useful to know, during program testing, that X has unified
|
|||
|
with some other variable even if it has not acquired a value.
|
|||
|
Thus, we want to record, somehow, that the variable X was
|
|||
|
mentioned in the original feature structure whereas the values of
|
|||
|
other features (person, number, etc.) were not.
|
|||
|
|
|||
|
Accordingly, g_/1 (distinct from g_/2) is used to mark all
|
|||
|
features that were mentioned in the original structure. If
|
|||
|
person is second in the canonical order, and tense is fifth in
|
|||
|
the canonical order (as before), then
|
|||
|
|
|||
|
tense:present..person:X =>
|
|||
|
g_(_,g_(g_(X),g_(_,g_(_,g_(g_(present),_)
|
|||
|
|
|||
|
And this is the representation actually used by GULP. Note that
|
|||
|
the use of g_/1 does not interfere with unification, because
|
|||
|
g_(present) will unify both with g_(Y) (an explicitly
|
|||
|
mentioned variable) and with an empty position.
|
|||
|
|
|||
|
|
|||
|
3.5. How translation is done
|
|||
|
|
|||
|
GULP loads a program by reading it, one term a a time, from
|
|||
|
the input file, and translating all the feature structures in each
|
|||
|
term into value lists. The term is then passed to the built-in
|
|||
|
predicate expand_term, which translates grammar rule (DCG)
|
|||
|
notation into plain Prolog. The result is then asserted into the
|
|||
|
knowledge base. There are two exceptions: a term that begins with
|
|||
|
`:-' is executed immediately, just as in ordinary Prolog, and a
|
|||
|
g_features declaration is given special treatment to be
|
|||
|
described below.
|
|||
|
|
|||
|
To make translation possible, GULP maintains a stored set of
|
|||
|
forward translation schemas, plus one backward schema. For
|
|||
|
example, a program that uses the features a, b, and c
|
|||
|
(encountered in that order) will result in the creation of the
|
|||
|
schemas:
|
|||
|
|
|||
|
g_forward_schema(a,X,g_(X,_)).
|
|||
|
g_forward_schema(b,X,g_(_,g_(X,_))).
|
|||
|
g_forward_schema(c,X,g_(_,g_(_,g_(X,_)))).
|
|||
|
|
|||
|
g_backward_schema(a:X..b:Y..c:Z,g_(X,g_(Y,g_(Z,_)))).
|
|||
|
|
|||
|
Each forward schema contains a feature name, a variable for the
|
|||
|
feature value, and the minimal corresponding value list. To
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
18
|
|||
|
|
|||
|
translate the feature structure a:xx..b:yy..c:zz, GULP will
|
|||
|
mark each of the feature values with g_(...), and then call, in
|
|||
|
succession,
|
|||
|
|
|||
|
g_forward_schema(a,g_(xx), ... ),
|
|||
|
g_forward_schema(b,g_(yy), ... ),
|
|||
|
g_forward_schema(c,g_(zz), ... ) ...
|
|||
|
|
|||
|
and unify the resulting value lists. The result will be the same
|
|||
|
regardless of the order in which the calls are made. To translate
|
|||
|
a complex Prolog term, GULP first converts it into a list using
|
|||
|
`=..', then recursively translates all the elements of the list
|
|||
|
except the first, then converts the result back into a term.
|
|||
|
|
|||
|
Backward translation is easier; GULP simply unifies the
|
|||
|
value list with the second argument of g_backward_schema, and
|
|||
|
the first argument immediately yields a rough translation. It is
|
|||
|
rough in two ways: it mentions all the features in the grammar,
|
|||
|
and it contains g_(...) marking all the feature values that were
|
|||
|
mentioned in the original feature structure. The finished
|
|||
|
translation is obtained by discarding all features whose values
|
|||
|
are not marked by g_(...), and removing the g_(...) from values
|
|||
|
that contain it.
|
|||
|
|
|||
|
The translation schemas are built automatically. Whenever a
|
|||
|
new feature is encountered, a forward schema is built for it, and
|
|||
|
the pre-existing backward schema, if any, is replaced by a new
|
|||
|
one. A g_features declaration causes the immediate generation of
|
|||
|
schemas for all the features in it, in the order given. In
|
|||
|
addition, GULP maintains a current g_features clause at all
|
|||
|
times that lists all the features actually encountered, whether or
|
|||
|
not they were originally declared.
|
|||
|
|
|||
|
|
|||
|
4. GULP in practical use
|
|||
|
|
|||
|
4.1. A simple definite clause grammar
|
|||
|
|
|||
|
Figure 7 shows the grammar from Figure 3 implemented with
|
|||
|
the definite clause grammar (DCG) parser that is built into
|
|||
|
Prolog. Each nonterminal symbol has a GULP feature structure as
|
|||
|
its only argument.
|
|||
|
|
|||
|
Parsing is done top-down. The output of the program reflects
|
|||
|
the feature structures built during parsing. For example:
|
|||
|
|
|||
|
?- test1.
|
|||
|
[max,sees,bill] (String being parsed)
|
|||
|
sem: pred: SEES (Displayed feature structure)
|
|||
|
arg1: BILL
|
|||
|
arg2: MAX
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
19
|
|||
|
|
|||
|
Figure 8 shows the same grammar written in a more PATR-like
|
|||
|
style. Instead of using feature structures in argument positions,
|
|||
|
this program uses variables for arguments, then unifies each
|
|||
|
variable with appropriate feature structures as a separate
|
|||
|
operation. This is slightly less efficient but can be easier to
|
|||
|
read, particularly when the unifications to be performed are
|
|||
|
complex.
|
|||
|
|
|||
|
In this program, the features of np and vp are called
|
|||
|
NPfeatures and VPfeatures respectively. More commonly, the
|
|||
|
features of np, vp, and so on are in variables called NP, VP,
|
|||
|
and the like. Be careful not to confuse upper- and lower-case
|
|||
|
symbols.
|
|||
|
|
|||
|
The rules in Figure 8 could equally well have been written
|
|||
|
with the unifications before the constituents to be parsed. That
|
|||
|
is, we can write either
|
|||
|
|
|||
|
s(Sfeatures) --> np(NPfeatures), vp(VPfeatures),
|
|||
|
{ Sfeatures = ... }.
|
|||
|
|
|||
|
or
|
|||
|
|
|||
|
s(Sfeatures) --> { Sfeatures = ... },
|
|||
|
np(NPfeatures), vp(VPfeatures).
|
|||
|
|
|||
|
Because unification is order-independent, the choice affects
|
|||
|
efficiency but not correctness. The only exception is that some
|
|||
|
rules can loop when written one way but not the other. Thus
|
|||
|
|
|||
|
s(S1) --> s(S2), { S1 = x:a, S2 = x:b }.
|
|||
|
|
|||
|
loops, whereas
|
|||
|
|
|||
|
s(S1) --> { S1 = x:a, S2 = x:b }, s(S2).
|
|||
|
|
|||
|
does not, because in the latter case S2 is instantiated to a
|
|||
|
value that must be distinct from S1 before s(S2) is parsed.
|
|||
|
|
|||
|
|
|||
|
4.2. A hold mechanism for unbounded movements
|
|||
|
|
|||
|
Unlike a phrase-structure grammar, a unification-based
|
|||
|
grammar can handle unbounded movements. That is, it can parse
|
|||
|
sentences in which some element appears to have been moved from
|
|||
|
its normal position across an arbitrary amount of structure.
|
|||
|
|
|||
|
Such a movement occurs in English questions. The question-
|
|||
|
word (who, what, or the like) always appears at the beginning of
|
|||
|
the sentence. Within the sentence, one of the places where a noun
|
|||
|
phrase could have appeared is empty:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
20
|
|||
|
|
|||
|
The boy said the dog chased the cat.
|
|||
|
What did the boy say _ chased the cat? (The dog.)
|
|||
|
What did the boy say the dog chased _? (The cat.)
|
|||
|
|
|||
|
Ordinary phrase-structure rules cannot express the fact that only
|
|||
|
one noun phrase is missing. Constituents introduced by phrase-
|
|||
|
structure rules are either optional or obligatory. If noun phrases
|
|||
|
are obligatory, they can't be missing at all, and if they are
|
|||
|
optional, any number of them can be missing at the same time.
|
|||
|
|
|||
|
Chomsky (1957) analyzed such sentences by generating what in
|
|||
|
the position of the missing noun phrase, then moving it to the
|
|||
|
beginning of the sentence by means of a transformation. This is
|
|||
|
the generally accepted analysis.
|
|||
|
|
|||
|
To parse such sentences, one must undo the movement. This is
|
|||
|
achieved through a hold stack. On encountering what, the parser
|
|||
|
does not parse it, but rather puts it on the stack and carries it
|
|||
|
along until it is needed. Later, when a noun phrase is expected
|
|||
|
but not found, the parser can pop what off the stack and use it.
|
|||
|
|
|||
|
The hold stack is a list to which elements can be added at
|
|||
|
the beginning. Initially, its value is [] (the empty list). To
|
|||
|
parse a sentence, the parser must:
|
|||
|
|
|||
|
(1) Pass the hold stack to the NP, which may add or remove
|
|||
|
items.
|
|||
|
(2) Pass the possibly modified stack to the VP, which may
|
|||
|
modify it further.
|
|||
|
|
|||
|
In traditional notation, the rule we need is:
|
|||
|
|
|||
|
S --> NP VP
|
|||
|
|
|||
|
<20> <20><> <20><> <20> <20> <20><> <20> <20> <20><>
|
|||
|
<20> hold:<3A> in: H1 <20><> <20> hold:<3A> in: H1 <20><> <20> hold:<3A> in: H2 <20><>
|
|||
|
<20> <20> out: H3 <20><> <20> <20> out: H2 <20><> <20> <20> out: H3 <20><>
|
|||
|
<20> <20> <20><> <20> <20> <20><> <20> <20> <20><>
|
|||
|
|
|||
|
Here hold:in is the stack before parsing a given constituent,
|
|||
|
and hold:out is the stack after parsing that same constituent.
|
|||
|
Notice that three different states of the stack -- H1, H2, and
|
|||
|
H3 -- are allowed for.
|
|||
|
|
|||
|
Figure 9 shows a complete grammar built with rules of this
|
|||
|
type. There are two rules expanding S. One is the one above (S -->
|
|||
|
NP VP). The other one accepts what did at the beginning of the
|
|||
|
sentence, places what on the stack, and proceeds to parse an NP
|
|||
|
and VP. Somewhere in the NP or VP -- or in a subordinate S
|
|||
|
embedded therein -- the parser will use the rule
|
|||
|
|
|||
|
np(NP) --> [], { NP = hold: (in:[what|H1]..out:H1) }.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
21
|
|||
|
|
|||
|
thereby removing what from the stack.
|
|||
|
|
|||
|
|
|||
|
4.3. Building complex semantic structures
|
|||
|
|
|||
|
Figure 10 shows a GULP reimplementation of a program by
|
|||
|
Johnson and Klein (1986) that makes extensive use of in and out
|
|||
|
features to pass information around the parse tree. Johnson and
|
|||
|
Klein's key insight is that the logical structure of a sentence is
|
|||
|
largely specified by the determiners. For instance, A man saw a
|
|||
|
donkey expresses a simple proposition with universally quantified
|
|||
|
variables, but Every man saw a donkey expresses an "if-then"
|
|||
|
relationship (If X is a man then X saw a donkey). On the syntactic
|
|||
|
level, every modifies only man, but semantically, it gives the
|
|||
|
entire sentence a different structure.
|
|||
|
|
|||
|
Accordingly, Johnson and Klein construct their grammar so
|
|||
|
that almost all the semantic structure is built by the
|
|||
|
determiners. Each determiner must receive, from elsewhere in the
|
|||
|
sentence, semantic representations for its scope and its
|
|||
|
restrictor. The scope of a determiner is the main predicate of the
|
|||
|
clause, and the restrictor is an additional condition imposed by
|
|||
|
the NP to which the determiner belongs. For instance, in Every man
|
|||
|
saw a donkey, the determiner every has scope saw a donkey and
|
|||
|
restrictor man.
|
|||
|
|
|||
|
Figure 10 shows a reimplementation, in GULP, of a sample
|
|||
|
program Johnson and Klein wrote in PrAtt (a different extension of
|
|||
|
Prolog). The semantic representations built by this program are
|
|||
|
those used in Discourse Representation Theory (Kamp, 1981;
|
|||
|
Spencer-Smith, 1987). The meaning of a sentence or discourse is
|
|||
|
represented by a discourse representation structure (DRS) such as:
|
|||
|
|
|||
|
[1,2,man(1),donkey(2),saw(1,2)]
|
|||
|
|
|||
|
Here 1 and 2 stand for entities (people or things), end man(1),
|
|||
|
donkey(2), and saw(1,2) are conditions that these entities
|
|||
|
must meet. The discourse is true if there are two entities such
|
|||
|
that 1 is a man, 2 is a donkey, and 1 saw 2. In other words, "A
|
|||
|
man saw a donkey." The order of the list elements is
|
|||
|
insignificant, and the program builds the list backward, with
|
|||
|
indices and conditions mixed together.
|
|||
|
|
|||
|
A DRS can contain other DRSes embedded in a variety of ways.
|
|||
|
In particular, one of the conditions within a DRS can have the
|
|||
|
form
|
|||
|
|
|||
|
DRS1 > DRS2
|
|||
|
|
|||
|
which means: "This condition is satisfied if for each set of
|
|||
|
entities that satisfy DRS1, it is also possible to satisfy DRS2."
|
|||
|
For example:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
22
|
|||
|
|
|||
|
[1,man(1), [2,donkey(2)] > [saw(1,2)] ]
|
|||
|
|
|||
|
"There is an entity 1 such that 1 is a man, and for every entity 2
|
|||
|
that is a donkey, 1 saw 2." That is, "Some man saw every donkey."
|
|||
|
Again,
|
|||
|
|
|||
|
[ [1,man(1)] > [2,donkey(2)] ]
|
|||
|
|
|||
|
means "every man saw a donkey" -- that is, "for every entity 1
|
|||
|
such that 1 is a man, there is an entity 2 which is a donkey."
|
|||
|
|
|||
|
Parsing a sentence begins with the rule:
|
|||
|
|
|||
|
s(S) --> { S = sem:A, NP = sem:A,
|
|||
|
S = syn:B, VP = syn:B,
|
|||
|
NP = sem:scope:C, VP = sem:C,
|
|||
|
VP = syn:arg1:D, NP = syn:index:D }, np(NP), vp(VP).
|
|||
|
|
|||
|
This rule stipulates the following things:
|
|||
|
|
|||
|
(1) An S consists of an NP and a VP.
|
|||
|
|
|||
|
(2) The semantic representation of the S is the same as that of
|
|||
|
the NP, i.e., is built by the rules that parse the NP.
|
|||
|
|
|||
|
(3) The syntactic feature structure (syn) of the S is that of the
|
|||
|
NP. Crucially, this contains the indices of the subject (arg1)
|
|||
|
and object (arg2).
|
|||
|
|
|||
|
(4) The scope of the NP (and hence of its determiner) is the
|
|||
|
semantic representation of the VP.
|
|||
|
|
|||
|
(5) The index of the verb's subject (arg1) is that of the NP
|
|||
|
mentioned in this rule.
|
|||
|
|
|||
|
Other rules do comparable amounts of work, and space precludes
|
|||
|
explaining them in detail here. (See Johnson and Klein 1985, 1986
|
|||
|
for further explanation.) By unifying appropriate in and out
|
|||
|
features, the rules perform a complex computation in an order-
|
|||
|
independent way.
|
|||
|
|
|||
|
|
|||
|
4.4. Bottom-up parsing
|
|||
|
|
|||
|
GULP is not tied to Prolog's built-in DCG parser. It can be
|
|||
|
used with any other parser implemented in Prolog. Figure 11 shows
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
23
|
|||
|
|
|||
|
how GULP can be used with the BUP bottom-up parser developed by
|
|||
|
Matsumoto et al. (1986).6
|
|||
|
|
|||
|
In bottom-up parsing, the typical question is not "How do I
|
|||
|
parse an NP?" but rather, "Now that I've parsed an NP, what do I
|
|||
|
do with it?" BUP puts the Prolog search mechanism to good use in
|
|||
|
answering questions like this.
|
|||
|
|
|||
|
During a BUP parse, two kinds of goals occur. A goal such as
|
|||
|
|
|||
|
?- np(s,NPf,Sf,[chased,the,cat],[]).
|
|||
|
|
|||
|
means: "An NP has just been accepted; its features are contained
|
|||
|
in NPf. This occurred while looking for an S with features Sf.
|
|||
|
Immediately after parsing the NP, the input string was
|
|||
|
[chased,the,cat]. After parsing the S, it will be []."
|
|||
|
|
|||
|
The other type of goal is
|
|||
|
|
|||
|
?- goal(vp,VPf,[chased,the,cat],[]).
|
|||
|
|
|||
|
This means "Parse a VP with features VPf, starting with the input
|
|||
|
string [chased,the,cat] and ending up with []." This is like
|
|||
|
the DCG goal
|
|||
|
|
|||
|
?- vp(VPf,[chased,the,cat],[]).
|
|||
|
|
|||
|
except that the parsing is to be done bottom-up.
|
|||
|
|
|||
|
To see how these goals are constructed, imagine replacing
|
|||
|
the top-down parsing rule
|
|||
|
|
|||
|
s --> np, vp.
|
|||
|
|
|||
|
with the bottom-up rule
|
|||
|
|
|||
|
np, vp --> s.
|
|||
|
|
|||
|
This rule should be used when the parser is looking for a rule
|
|||
|
that will tell it how to use an NP it has just found. So np(...)
|
|||
|
should be the head of the Prolog clause. Ignoring feature
|
|||
|
unifications, the clause will be:
|
|||
|
|
|||
|
np(G,NPf,Gf,S1,S3) :- goal(vp,VPf,S1,S2),
|
|||
|
s(G,Sf,Gf,S2,S3).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
6 It has been suggested that a combination of GULP
|
|||
|
and BUP should be known as BURP. This suggestion has
|
|||
|
not been acted upon.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
24
|
|||
|
|
|||
|
That is: "Having just found an NP with features NPf, parse a VP
|
|||
|
with features VPf. You will then have completed an S, so look for
|
|||
|
a clause that tells you what to do with it."
|
|||
|
|
|||
|
Here S1, S2, and S3 represent the input string initially,
|
|||
|
after parsing the VP, and after completing the S. G is the higher
|
|||
|
constituent that was being sought when the NP was found, and Gf
|
|||
|
contains its features. If, when the S is completed, it turns out
|
|||
|
that an S was being sought (the usual case), then execution can
|
|||
|
finish with the terminal rule
|
|||
|
|
|||
|
s(s,F,F,X,X).
|
|||
|
|
|||
|
Otherwise another clause for s(...) must be searched for.
|
|||
|
|
|||
|
Much of the work of BUP is done by the goal-forming
|
|||
|
predicate goal, defined thus:
|
|||
|
|
|||
|
goal(G,Gf,S1,S3) :-
|
|||
|
word(W,Wf,S1,S2),
|
|||
|
NewGoal =.. [W,G,Wf,Gf,S2,S3],
|
|||
|
call(NewGoal).
|
|||
|
|
|||
|
That is (ignoring features): "To parse a G in input string S1
|
|||
|
leaving the remaining input in S3, first accept a word, then
|
|||
|
construct a new goal depending on its category (W)." For example,
|
|||
|
the query
|
|||
|
|
|||
|
?- goal(s,Sf,[the,dog,barked],S3).
|
|||
|
|
|||
|
will first call
|
|||
|
|
|||
|
?- word(W,Wf,[the,dog,barked],[dog,barked]).
|
|||
|
|
|||
|
thereby instantiating W to det and Wf to the word's features,
|
|||
|
and then construct and call the goal
|
|||
|
|
|||
|
?- det(s,Wf,Sf,[dog,barked],S3).
|
|||
|
|
|||
|
That is: "I've just completed a det and am trying to parse an s.
|
|||
|
What do I do next?" A rule such as
|
|||
|
|
|||
|
det, n --> np
|
|||
|
|
|||
|
(or rather its BUP equivalent) can be invoked next, to accept
|
|||
|
another word (a noun) and complete an NP.
|
|||
|
|
|||
|
|
|||
|
5. Comparison with other systems
|
|||
|
|
|||
|
5.1. GULP versus PATR-II
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
25
|
|||
|
|
|||
|
PATR-II (Shieber 1986a, b) is the most widely used software
|
|||
|
tool for implementing unification-based grammars, as well as the
|
|||
|
most mature and sophisticated. It differs from GULP in three main
|
|||
|
ways:
|
|||
|
|
|||
|
(1) Whereas GULP is an extension of Prolog, PATR-II is a new self-
|
|||
|
contained programming language.
|
|||
|
|
|||
|
(2) Whereas GULP allows the use of any parsing algorithm, PATR-II
|
|||
|
provides one specific parser (left-corner, Earley, or Cocke-
|
|||
|
Kasami-Younger, depending on the version).
|
|||
|
|
|||
|
(3) Whereas GULP grammar rules treat feature structures as data
|
|||
|
items, PATR-II grammar rules state equations on feature values.
|
|||
|
|
|||
|
Of these, (3) makes the biggest practical difference. The
|
|||
|
rule which GULP writes as
|
|||
|
|
|||
|
s(person:X..number:Y) -->
|
|||
|
np(person:X..number:Y),
|
|||
|
vp(person:X..number:Y).
|
|||
|
|
|||
|
(assuming use of the DCG parser) is rendered in PATR-II as:
|
|||
|
|
|||
|
Rule S --> NP VP:
|
|||
|
<S number> = <NP number>
|
|||
|
<S number> = <VP number>
|
|||
|
<S person> = <NP person>
|
|||
|
<S person> = <VP person>.
|
|||
|
|
|||
|
or the like. Paths are permitted, of course; one could write <NP
|
|||
|
syn agr number> to build a more complex structure.
|
|||
|
|
|||
|
Here S, NP, and VP are not pure variables; the equations
|
|||
|
|
|||
|
<S cat> = s
|
|||
|
<NP cat> = np
|
|||
|
<VP cat> = vp
|
|||
|
|
|||
|
(or the equivalent) are implicit. Further abbreviatory power comes
|
|||
|
from templates, which are predefined sets of features and values.
|
|||
|
Thus, instead of writing the lexical entry
|
|||
|
|
|||
|
Word sleeps: <cat> = v
|
|||
|
<person> = third
|
|||
|
<number> = singular
|
|||
|
<subcat> = intransitive.
|
|||
|
|
|||
|
the PATR-II programmer can define the template
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
26
|
|||
|
|
|||
|
Let ThirdSingVerb be <cat> = v
|
|||
|
<person> = third
|
|||
|
<number> = singular.
|
|||
|
|
|||
|
and then write:
|
|||
|
|
|||
|
Word sleeps: ThirdSingVerb
|
|||
|
<subcat> = intransitive.
|
|||
|
|
|||
|
Word chases: ThirdSingVerb
|
|||
|
<subcat> = transitive.
|
|||
|
|
|||
|
The GULP equivalent of a template is a Prolog fact such as:
|
|||
|
|
|||
|
thirdsingverb(person:third..number:singular).
|
|||
|
|
|||
|
Lexical entries can then use this as an abbreviatory device:
|
|||
|
|
|||
|
v(Vf) --> [sleeps], { thirdsingverb(Vf),
|
|||
|
Vf = subcat:intransitive }.
|
|||
|
|
|||
|
v(Vf) --> [chases], { thirdsingverb(Vf),
|
|||
|
Vf = subcat:transitive }.
|
|||
|
|
|||
|
(There is no cat:v here because in the DCG parser, categories are
|
|||
|
functors rather than feature values.)
|
|||
|
|
|||
|
Unlike GULP, PATR-II provides for default inheritance. That
|
|||
|
is, the programmer can invoke a template and then change some of
|
|||
|
the values that it supplies, thus:
|
|||
|
|
|||
|
Word does: ThirdSingVerb
|
|||
|
<cat> = auxverb.
|
|||
|
|
|||
|
This means: "Does is a ThirdSingVerb except that its category is
|
|||
|
not v but rather auxverb." PATR-II also provides for lexical
|
|||
|
redundancy rules that transform one lexical entry into another,
|
|||
|
e.g., building a passive verb from every active verb.
|
|||
|
|
|||
|
Both of these capabilities are absent from GULP per se, but
|
|||
|
they could be built into a parser written in GULP. Indeed, many
|
|||
|
contrasts between GULP and PATR-II reflect the fact that PATR-II
|
|||
|
is a custom-built environment for implementing grammars that fit a
|
|||
|
particular mold, while GULP is a minimal extension to a much more
|
|||
|
general-purpose programming language.
|
|||
|
|
|||
|
One advantage of GULP is that the full range of Prolog data
|
|||
|
structures is available. Shieber (1986a:28-32) equips each verb
|
|||
|
with an ordered list of NPs that are its syntactic arguments
|
|||
|
(subject, object, etc.). But there are no lists in PATR-II, so
|
|||
|
Shieber has to construct them as nested feature structures:
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
27
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> first: ...first element... <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> rest: <20> first: ...second element... <20> <20>
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
<20> <20> rest: <20> first: ...third element... <20> <20> <20>
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> <20> <20> rest: <20> first: ...fourth element... <20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20> rest: end <20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
|
|||
|
This may be desirable on grounds of theoretical parsimony, but it
|
|||
|
is notationally awkward. In GULP, one can simply write
|
|||
|
[X1,X2,X3,X4], where X1, X2, X3, and X4 are variables,
|
|||
|
constants, feature structures, or terms of any other kind.
|
|||
|
|
|||
|
|
|||
|
5.2. GULP versus PrAtt
|
|||
|
|
|||
|
PrAtt (Prolog with Attributes), described briefly by Johnson
|
|||
|
and Klein (1986), is a PATR-like extension of Prolog. In PrAtt,
|
|||
|
feature structure equations are treated as Prolog goals. An
|
|||
|
example is the DCG rule:
|
|||
|
|
|||
|
s(Sf) --> np(NPf), vp(VPf),
|
|||
|
{ Sf:number = NPf:number,
|
|||
|
Sf:number = VPf:number,
|
|||
|
Sf:person = NPf:person,
|
|||
|
Sf:person = VPf:person }.
|
|||
|
|
|||
|
This looks almost like GULP syntax, but the meaning is different.
|
|||
|
NPf:number is not a Prolog term, but rather an evaluable
|
|||
|
expression; at execution time, it is replaced by the number
|
|||
|
element of structure NPf.
|
|||
|
|
|||
|
Compared to GULP, PrAtt makes a much bigger change to the
|
|||
|
semantics of Prolog. GULP merely translates data into data
|
|||
|
(changing the format from feature structures to value lists), but
|
|||
|
PrAtt translates data into extra operations.
|
|||
|
|
|||
|
An example will make this clearer. In order to execute
|
|||
|
Sf:number = NPf:number, PrAtt must extract the number
|
|||
|
features of Sf and NPf, then unify them. In Johnson and Klein's
|
|||
|
implementation, this extraction is done at run time; that is, on
|
|||
|
find the expression Sf:number, the PrAtt interpreter looks at
|
|||
|
the contents of Sf, and then replaces Sf:number with the value
|
|||
|
of Sf's number feature.
|
|||
|
|
|||
|
This implies that the value of Sf is known. If it is not --
|
|||
|
for example, if the PrAtt-to-Prolog translation is being performed
|
|||
|
before running the program -- then extra goals must be inserted
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
28
|
|||
|
|
|||
|
into the program to extract the appropriate feature values. The
|
|||
|
single PrAtt goal Sf:number = NPf:number becomes at least
|
|||
|
three goals:
|
|||
|
|
|||
|
(1) Unify Sf with something that will put the number value
|
|||
|
into a unique variable (call it X).
|
|||
|
|
|||
|
(2) Unify NPf with something that will put its number value
|
|||
|
into a unique variable (call it Y).
|
|||
|
|
|||
|
(3) Unify X and Y.
|
|||
|
|
|||
|
To put this another way, whereas GULP modifies the syntax
|
|||
|
for Prolog terms, PrAtt modifies the unification algorithm, using
|
|||
|
three calls to the existing Prolog unification algorithm to
|
|||
|
perform one PrAtt unification.
|
|||
|
|
|||
|
|
|||
|
5.3. GULP versus AVAG
|
|||
|
|
|||
|
AVAG (Attribute-Value Grammar, Sedogbo 1986) is an
|
|||
|
implementation of generalized phrase structure grammar (GPSG), a
|
|||
|
framework for expressing linguistic analyses. A three-pass
|
|||
|
compiler translates AVAG notation into Prolog II. As such, AVAG is
|
|||
|
far more complex than GULP or PrAtt, and there is little point in
|
|||
|
making a direct comparison. Comparing AVAG to PATR-II would be
|
|||
|
instructive but is outside the scope of this paper.
|
|||
|
|
|||
|
AVAG is interesting because it uses the Prolog II built-in
|
|||
|
predicates dif (which means "this variable must never be
|
|||
|
instantiated to this value") and freeze ("wait until these
|
|||
|
variables are instantiated, then test them") to implement
|
|||
|
negative-valued and set-valued features respectively. For
|
|||
|
example, the rule
|
|||
|
|
|||
|
voit:
|
|||
|
<cat> = verb
|
|||
|
<person> /= 2
|
|||
|
<number> = sing.
|
|||
|
|
|||
|
uses dif to ensure that the person feature never equals 2, and
|
|||
|
|
|||
|
chaque:
|
|||
|
<cat> = art
|
|||
|
<gender> = [mas,fem]
|
|||
|
<number> = sing.
|
|||
|
|
|||
|
uses freeze to ensure that when the gender feature becomes
|
|||
|
instantiated, its value is mas or fem. There are no direct
|
|||
|
equivalents for dif or freeze in conventional (Edinburgh)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
29
|
|||
|
|
|||
|
Prolog; they could be implemented only by changing the inference
|
|||
|
engine.
|
|||
|
|
|||
|
|
|||
|
5.4. GULP versus STUF
|
|||
|
|
|||
|
STUF (Stuttgart Formalism) is a formal language for
|
|||
|
describing unification-based grammars. It is more comprehensive
|
|||
|
than PATR-II and as yet is only partly implemented (Bouma et al.
|
|||
|
1988).
|
|||
|
|
|||
|
Comparing STUF to GULP would be rather like comparing linear
|
|||
|
algebra to Fortran; the systems are not in the same category.
|
|||
|
Nonetheless, STUF introduces a number of novel ideas that could be
|
|||
|
exploited in parsers or other systems written in GULP.
|
|||
|
|
|||
|
The biggest of these is nondestructive unification. In
|
|||
|
Prolog, unification is a destructive operation; terms that are
|
|||
|
being unified are replaced by their unifier. For example, if X =
|
|||
|
[a,_] and Y = [_,b], then after unifying X and Y, X = Y =
|
|||
|
[a,b]. In STUF, on the other hand, an expression such as
|
|||
|
|
|||
|
z = (x y)
|
|||
|
|
|||
|
creates a third structure z whose value is the unifier of x and
|
|||
|
y; x and y themselves are unaffected. Nondestructive unification
|
|||
|
can be implemented in Prolog by copying the terms before unifying
|
|||
|
them (Covington et al. 1988:204).
|
|||
|
|
|||
|
Further, if the unification fails, z gets the special value
|
|||
|
FAIL. If x and y are feature structures, and parts of them are
|
|||
|
unifiable but other parts are not, the non-unifiable parts will be
|
|||
|
represented by FAIL in the corresponding parts of z. This
|
|||
|
provides a way to implement negative-valued features. For example,
|
|||
|
to ensure that a verb is not third person singular, one can
|
|||
|
stipulate that when its person feature is unified with
|
|||
|
person:3, the result is FAIL.
|
|||
|
|
|||
|
In STUF, a feature can also have a set of alternatives as
|
|||
|
its value, and when two structures containing such sets are
|
|||
|
unified, the unifier is the set of all the unifiers of structures
|
|||
|
that would result from choosing different alternatives.
|
|||
|
|
|||
|
Finally, STUF exploits the fact that grammar rules can
|
|||
|
themselves be treated as feature structures. For example, the rule
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
30
|
|||
|
|
|||
|
|
|||
|
S --> NP VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> person:X <20> <20> person:X <20>
|
|||
|
<20> number:Y <20> <20> number:Y <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
(or more precisely the tree structure that it sanctions) can be
|
|||
|
expressed as the feature structure
|
|||
|
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> mother: <20> category: s <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> daughter_1: <20> category: np <20> <20>
|
|||
|
<20> <20> person: X <20> <20>
|
|||
|
<20> <20> number: Y <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> daughter_2: <20> category: vp <20> <20>
|
|||
|
<20> <20> person: X <20> <20>
|
|||
|
<20> <20> number: Y <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
STUF therefore implements grammar rules via "graph
|
|||
|
application," an operation that treats one feature structure
|
|||
|
(directed acyclic graph) as a function to be applied to another.
|
|||
|
Graph application is an operation with four arguments: (1) a
|
|||
|
graph expressing the function; (2) a graph to be treated as the
|
|||
|
argument; (3) a path indicating what part of the argument graph is
|
|||
|
to be unified with the function graph; and (4) a path indicating
|
|||
|
what part of the argument graph should be unified (destructively)
|
|||
|
with the result of the first unification. The ordinary GULP
|
|||
|
practice of simply unifying one graph with another is a special
|
|||
|
case of this.
|
|||
|
|
|||
|
|
|||
|
6.0. Future Prospects
|
|||
|
|
|||
|
6.1. Possible improvements
|
|||
|
|
|||
|
One disadvantage of GULP is that every feature structure
|
|||
|
must contain a position for every feature in the grammar. This
|
|||
|
makes feature structures larger and slower to process than they
|
|||
|
need be. By design, unused features often fall in the
|
|||
|
uninstantiated tail of the value list, and hence take up neither
|
|||
|
time nor space. But not all unused features have this good
|
|||
|
fortune. In practice, almost every value list contains gaps, i.e.,
|
|||
|
positions that will never be instantiated, but must be passed over
|
|||
|
in every unification.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
31
|
|||
|
|
|||
|
To reduce the number of gaps, GULP could be modified to
|
|||
|
distinguish different types of value lists. The feature structure
|
|||
|
for a verb needs a feature for tense; the feature structure for a
|
|||
|
noun does not. Value lists of different types would reserve the
|
|||
|
same positions for different features, skipping features that
|
|||
|
would never be used. Some kind of type marker, such as a unique
|
|||
|
functor, would be needed so that value lists of different types
|
|||
|
would not unify with each other.
|
|||
|
|
|||
|
Types of feature structures could be distinguished by the
|
|||
|
programmer -- e.g., by giving alternative g_features
|
|||
|
declarations -- or by modifying the GULP translator itself to look
|
|||
|
for patterns in the use of features.
|
|||
|
|
|||
|
|
|||
|
6.2. Keyword parameters via GULP
|
|||
|
|
|||
|
Unification-based grammar is not the only use for GULP.
|
|||
|
Feature structures are a good formalization of keyword-value
|
|||
|
argument lists.
|
|||
|
|
|||
|
Imagine a complicated graphics procedure that takes
|
|||
|
arguments indicating desired window size, maximum and minimum
|
|||
|
coordinates, and colors, all of which have default values. In
|
|||
|
Pascal, the procedure can only be called with explicit values for
|
|||
|
all the parameters:
|
|||
|
|
|||
|
OpenGraphics(480,640,-240,240,-320,320,green,black);
|
|||
|
|
|||
|
There could, however, be a convention that 0 means "take the
|
|||
|
default:"
|
|||
|
|
|||
|
OpenGraphics(0,0,0,0,0,0,red,blue);
|
|||
|
|
|||
|
Prolog can do slightly better by using uninstantiated arguments
|
|||
|
where defaults are wanted, and thereby distinguishing "default"
|
|||
|
from "zero":
|
|||
|
|
|||
|
:- open_graphics(_,_,_,_,_,_,red,blue).
|
|||
|
|
|||
|
In GULP, however, the argument of open_graphics can be a
|
|||
|
feature structure in which the programmer mentions only the non-
|
|||
|
default items:
|
|||
|
|
|||
|
:- open_graphics( foreground:red..background:blue ).
|
|||
|
|
|||
|
In this feature structure, the values for x_resolution,
|
|||
|
y_resolution, x_maximum, x_minimum, y_maximum, and
|
|||
|
y_minimum (or whatever they are called) are left uninstantiated
|
|||
|
because they are not mentioned. So in addition to facilitating the
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
32
|
|||
|
|
|||
|
implementation of unification-based grammars, GULP provides Prolog
|
|||
|
with a keyword argument system.
|
|||
|
|
|||
|
|
|||
|
References
|
|||
|
|
|||
|
Barton, G. Edward; Berwick, Robert C.; and Ristad, Eric Sven.
|
|||
|
1987. Computational complexity and natural language.
|
|||
|
Cambridge, Massachusetts: MIT Press.
|
|||
|
|
|||
|
Bouma, Gosse; K<>nig, Esther; and Uszkoreit, Hans. 1988. A flexible
|
|||
|
graph-unification formalism and its application to natural-
|
|||
|
language processing. IBM Journal of Research and Development
|
|||
|
32:170-184.
|
|||
|
|
|||
|
Bresnan, Joan, ed. 1982. The mental representation of grammatical
|
|||
|
relations. Cambridge, Massachusetts: MIT Press.
|
|||
|
|
|||
|
Chomsky, Noam. 1957. Syntactic structures. (Janua linguarum, 4.)
|
|||
|
The Hague: Mouton.
|
|||
|
|
|||
|
Chomsky, Noam. 1965. Aspects of the theory of syntax. Cambridge,
|
|||
|
Massachusetts: MIT Press.
|
|||
|
|
|||
|
Covington, Michael A. 1987. GULP 1.1: an extension of Prolog for
|
|||
|
unification-based grammar. ACMC Research Report 01-0021.
|
|||
|
Advanced Computational Methods Center, University of
|
|||
|
Georgia.
|
|||
|
|
|||
|
Covington, Michael A.; Nute, Donald; and Vellino, Andr<64>. 1988.
|
|||
|
Prolog programming in depth. Glenview, Ill.: Scott,
|
|||
|
Foresman.
|
|||
|
|
|||
|
Gazdar, Gerald; Klein, Ewan; Pullum, Geoffrey; and Sag, Ivan.
|
|||
|
Generalized phrase structure grammar. Cambridge,
|
|||
|
Massachusetts: Harvard University Press.
|
|||
|
|
|||
|
Giannesini, Francis; Kanoui, Henry; Pasero, Robert; and van
|
|||
|
Caneghem, Michel. 1986. Prolog. Wokingham, England: Addison-
|
|||
|
Wesley.
|
|||
|
|
|||
|
Johnson, Mark, and Klein, Ewan. 1985. A declarative formulation of
|
|||
|
Discourse Representation Theory. Paper presented at the
|
|||
|
summer meeting of the Association for Symbolic Logic, July
|
|||
|
15-20, 1985, Stanford University.
|
|||
|
|
|||
|
Johnson, Mark, and Klein, Ewan. 1986. Discourse, anaphora, and
|
|||
|
parsing. Report No. CSLI-86-63. Center for the Study of
|
|||
|
Language and Information, Stanford University. Also in
|
|||
|
Proceedings of Coling86 669-675.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
33
|
|||
|
|
|||
|
Joshi, Aravind K. 1986. The convergence of mildly context-
|
|||
|
sensitive grammar formalisms. Draft distributed at Stanford
|
|||
|
University, 1987.
|
|||
|
|
|||
|
Kamp, Hans. 1981. A theory of truth and semantic representation.
|
|||
|
Reprinted in Groenendijk, J.; Janssen, T. M. V.; and
|
|||
|
Stokhof, M., eds., Truth, interpretation, and information.
|
|||
|
Dordrecht: Foris, 1984.
|
|||
|
|
|||
|
Kaplan, Ronald M., and Bresnan, Joan. 1982. Lexical-Functional
|
|||
|
Grammar: a formal system for grammatical representation.
|
|||
|
Bresnan 1982:173-281.
|
|||
|
|
|||
|
Karttunen, Lauri. 1986a. D-PATR: a development environment for
|
|||
|
unification-based grammars. Report No. CSLI-86-61. Center
|
|||
|
for the Study of Language and Information, Stanford
|
|||
|
University. Shortened version in Proceedings of Coling86 74-
|
|||
|
80.
|
|||
|
|
|||
|
Karttunen, Lauri. 1986b. Features and values. Shieber et al. 1986
|
|||
|
(vol. 1), 17-36. Also in Proceedings of Coling84 28-33.
|
|||
|
|
|||
|
Matsumoto, Yuji; Tanaka, Hozumi; and Kiyono, Masaki. 1986. BUP: a
|
|||
|
bottom-up parsing system for natural languages. Michel van
|
|||
|
Caneghem and David Warren, eds., Logic programming and its
|
|||
|
applications 262-275. Norwood, N.J.: Ablex.
|
|||
|
|
|||
|
Pollard, Carl, and Sag, Ivan A. 1987. Information-based syntax and
|
|||
|
semantics, vol. 1: Fundamentals. (CSLI Lecture Notes, 13.)
|
|||
|
Center for the Study of Language and Information, Stanford
|
|||
|
University.
|
|||
|
|
|||
|
Sedogbo, Celestin. 1986. AVAG: an attribute/value grammar tool.
|
|||
|
FNS-Bericht 86-10. Seminar f<>r nat<61>rlich-sprachliche
|
|||
|
Systeme, Universit<69>t T<>bingen.
|
|||
|
|
|||
|
Shieber, Stuart M. 1986a. An introduction to unification-based
|
|||
|
approaches to grammar. (CSLI Lecture Notes, 4.) Center for
|
|||
|
the Study of Language and Information, Stanford University.
|
|||
|
|
|||
|
Shieber, Stuart M. 1986b. The design of a computer language for
|
|||
|
linguistic information. Shieber et al. (eds.) 1986 (vol. 1)
|
|||
|
4-26.
|
|||
|
|
|||
|
Shieber, Stuart M.; Pereira, Fernando C. N.; Karttunen, Lauri; and
|
|||
|
Kay, Martin, eds. A compilation of papers on unification-
|
|||
|
based grammar formalisms. 2 vols. bound as one. Report No.
|
|||
|
CSLI-86-48. Center for the Study of Language and
|
|||
|
Information, Stanford University.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
34
|
|||
|
|
|||
|
Spencer-Smith, Richard. 1987. Semantics and discourse
|
|||
|
representation. Mind and Language 2.1: 1-26.
|
|||
|
|
|||
|
|
|||
|
Appendix. GULP 2.0 User's Guide
|
|||
|
|
|||
|
A.1 Overview
|
|||
|
|
|||
|
GULP is a laboratory instrument, not a commercial product.
|
|||
|
Although reasonably easy to use, it lacks the panache and
|
|||
|
sophistication of Turbo Pascal or Arity Prolog 5.0. The emphasis
|
|||
|
is on getting the job done as simply as possible.
|
|||
|
|
|||
|
The final word on how GULP works is contained in the file
|
|||
|
GULP.ARI or GULP.PL, which you should consult whenever you have a
|
|||
|
question that is not answered here.
|
|||
|
|
|||
|
|
|||
|
A.2 Installation and access
|
|||
|
|
|||
|
On the VAX, GULP is already installed, and you reach it by
|
|||
|
the command
|
|||
|
|
|||
|
$ gulp
|
|||
|
|
|||
|
This puts you into a conventional Prolog environment (note: not a
|
|||
|
Quintus Prolog split-screen environment) in which the GULP built-
|
|||
|
in predicates are available.
|
|||
|
|
|||
|
The IBM PC version of GULP is supplied as a modified copy of
|
|||
|
Arity Prolog Interpreter 4.0. It is for use only on machines for
|
|||
|
which Arity Prolog is licensed and is not for distribution outside
|
|||
|
the AI Research Group.
|
|||
|
|
|||
|
Many of the GULP file names are the same as files used by
|
|||
|
the unmodified Arity Prolog Interpreter. It is therefore important
|
|||
|
that GULP be installed in a different directory.
|
|||
|
|
|||
|
To run GULP you also need a full-screen editor that is
|
|||
|
accessible by the command:
|
|||
|
|
|||
|
edit filename
|
|||
|
|
|||
|
GULP passes commands of this form to DOS when invoking the editor.
|
|||
|
We usually use AHED.COM, renamed EDIT.COM, for the purpose, but
|
|||
|
you can use any editor that produces ASCII files.
|
|||
|
|
|||
|
|
|||
|
A.3 How to run programs
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
35
|
|||
|
|
|||
|
GULP is simply a version of Prolog with more built-in
|
|||
|
predicates added. All the functions and features of Prolog7 are
|
|||
|
still available and work exactly as before. GULP is used in
|
|||
|
exactly the same way as Prolog except that:
|
|||
|
|
|||
|
(1) Programs containing feature structures must be loaded
|
|||
|
via the built-in predicate load, not consult or reconsult. The
|
|||
|
reason is that consult or reconsult would load the feature
|
|||
|
structures into memory without converting them into value lists.
|
|||
|
Prolog will do this without complaining, but GULP programs will
|
|||
|
not work. Never use consult or reconsult to load anything that
|
|||
|
contains GULP feature structures.
|
|||
|
|
|||
|
(2) You must always invoke the editor with the GULP command
|
|||
|
ed, not with whatever command you would use in Prolog. This is
|
|||
|
important because your ordinary editing command would
|
|||
|
automatically invoke reconsult after editing; ed invokes load
|
|||
|
instead.
|
|||
|
|
|||
|
(3) You cannot use feature structure notation in a query
|
|||
|
because queries do not go through the translator. Write your
|
|||
|
program so that you can invoke all the necessary predicates
|
|||
|
without having to type feature structures on the command line.
|
|||
|
|
|||
|
|
|||
|
A.4 Built-in predicates usually used as commands
|
|||
|
|
|||
|
?- load filename.
|
|||
|
|
|||
|
Loads the program on file filename into memory via the GULP
|
|||
|
translator. load is like reconsult in that, whenever a
|
|||
|
predicate is encountered that is already defined, the old
|
|||
|
definition is discarded before the new definition is loaded. This
|
|||
|
means that all clauses defining a predicate must be on the same
|
|||
|
file, but they need not be contiguous. Further, you can load
|
|||
|
definitions of different predicates from different files without
|
|||
|
conflict. Further, you can embed a call to load in a program to
|
|||
|
make it load another program.
|
|||
|
|
|||
|
If the file name is not in quotes, the ending .GLP is added. If
|
|||
|
the file name contains a period, it must be typed in quotes
|
|||
|
(single or double).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
7 Except the module system, which uses the colon
|
|||
|
(':') for its own purposes and conflicts with GULP
|
|||
|
syntax.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
36
|
|||
|
|
|||
|
?- load.
|
|||
|
|
|||
|
Loads (again) the file that was used in the most recent call to
|
|||
|
load or ed.
|
|||
|
|
|||
|
|
|||
|
?- ed filename.
|
|||
|
|
|||
|
Calls the editor to process file filename, then loads that file.
|
|||
|
|
|||
|
|
|||
|
?- ed.
|
|||
|
|
|||
|
Edits and loads (again) the file that was used in the most recent
|
|||
|
call to load or ed.
|
|||
|
|
|||
|
|
|||
|
?- list P/N.
|
|||
|
|
|||
|
Lists all clauses that define the predicate P with N arguments,
|
|||
|
provided these clauses were loaded with ed or load. (Note: In
|
|||
|
the case of grammar rules, the number of arguments includes the
|
|||
|
arguments automatically supplied by the Prolog grammar rule
|
|||
|
translator.)
|
|||
|
|
|||
|
|
|||
|
?- list P.
|
|||
|
|
|||
|
Lists all clauses that define the predicate P with any number of
|
|||
|
arguments, provided these clauses were loaded with ed or load.
|
|||
|
|
|||
|
|
|||
|
?- list.
|
|||
|
|
|||
|
Lists all clauses that were loaded with ed or load.
|
|||
|
|
|||
|
|
|||
|
?- new.
|
|||
|
|
|||
|
Clears the workspace; removes from memory all clauses that were
|
|||
|
loaded with ed or load. (Does not delete clauses that were
|
|||
|
placed into memory by consult, reconsult, or assert.)
|
|||
|
|
|||
|
|
|||
|
A.5 Built-in predicates usually used within the program
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
37
|
|||
|
|
|||
|
g_translate(FeatureStructure,ValueList)
|
|||
|
|
|||
|
Translates a feature structure into a value list, or vice versa.
|
|||
|
Used when you must interconvert internal and external
|
|||
|
representations at run time (e.g., to input or output them). For
|
|||
|
example, the following will accept a feature structure in GULP
|
|||
|
notation from the keyboard, translate it into a value list, and
|
|||
|
pass the value list to your predicate test:
|
|||
|
|
|||
|
?- read(X), g_translate(X,Y), test(Y).
|
|||
|
|
|||
|
The following translates a feature structure X from internal to
|
|||
|
external representation and prints it out:
|
|||
|
|
|||
|
... g_translate(Y,X), write(Y).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
display_feature_structure(X)
|
|||
|
|
|||
|
Displays X in a convenient indented notation (not GULP syntax),
|
|||
|
where X is either a feature structure or a value list.
|
|||
|
|
|||
|
|
|||
|
g_display(X)
|
|||
|
|
|||
|
Equivalent to display_feature_structure(X); retained for
|
|||
|
compatibility with GULP 1.
|
|||
|
|
|||
|
|
|||
|
g_printlength(A,N)
|
|||
|
|
|||
|
Where A is an atom, instantiates N to the number of characters
|
|||
|
needed to print it. Useful in constructing your own indented
|
|||
|
output routines.
|
|||
|
|
|||
|
|
|||
|
writeln(X)
|
|||
|
|
|||
|
If X is a list, writes each element of X on a separate line and
|
|||
|
then begins a new line. If X is not a list, writes X and then
|
|||
|
begins a new line. Examples:
|
|||
|
|
|||
|
writeln('This is a message.').
|
|||
|
|
|||
|
writeln(['This is a','two-line message.']).
|
|||
|
|
|||
|
Lists within lists are not processed recursively. The elements of
|
|||
|
the outermost list are printed one per line, and lists within it
|
|||
|
are printed as lists.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
38
|
|||
|
|
|||
|
append(List1,List2,List3)
|
|||
|
|
|||
|
Concatenates List1 and List2 giving List3, or splits List3
|
|||
|
into List1 and List2.
|
|||
|
|
|||
|
|
|||
|
member(Element,List)
|
|||
|
|
|||
|
Succeeds if Element is an element of List. If Element is
|
|||
|
uninstantiated, it will be instantiated, upon backtracking, to
|
|||
|
each successive element of List.
|
|||
|
|
|||
|
|
|||
|
remove_duplicates(List1,List2)
|
|||
|
|
|||
|
Removes duplicate elements from List1 giving List2.
|
|||
|
|
|||
|
|
|||
|
retractall(P)
|
|||
|
|
|||
|
Retracts (abolishes) all clauses whose predicate is P.
|
|||
|
|
|||
|
|
|||
|
phrase(Constituent,InputString)
|
|||
|
|
|||
|
Provides a simplified way to call a parser written with DCG rules;
|
|||
|
for example, the goal ?- phrase(s,[the,dog,barks]) is
|
|||
|
equivalent to ?- s([the,dog,barks],[]).
|
|||
|
|
|||
|
|
|||
|
copy(X,Y)
|
|||
|
|
|||
|
Copies term X, giving term Y. These terms are the same except
|
|||
|
that all uninstantiated variables in X are replaced by new
|
|||
|
uninstantiated variables in Y, arranged in the same way.
|
|||
|
Variables in Y can then be instantiated without affecting X.
|
|||
|
|
|||
|
|
|||
|
call_if_possible(Goal)
|
|||
|
|
|||
|
Executes Goal, or fails without an error message if there are no
|
|||
|
clauses for Goal. (In Quintus Prolog, the program crashes with an
|
|||
|
error message if there is an attempt to query a goal for which
|
|||
|
there are no clauses.)
|
|||
|
|
|||
|
|
|||
|
g_fs(X)
|
|||
|
|
|||
|
Succeeds if X is an untranslated feature structure, i.e., a term
|
|||
|
whose principal functor is ':', '..', or '::'.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
39
|
|||
|
|
|||
|
g_not_fs(X)
|
|||
|
|
|||
|
Succeeds if X is not an untranslated feature structure.
|
|||
|
|
|||
|
|
|||
|
g_vl(X)
|
|||
|
|
|||
|
Succeeds if X is a value list (the internal representation of a
|
|||
|
feature structure).
|
|||
|
|
|||
|
|
|||
|
A.6 Other built-in predicates
|
|||
|
|
|||
|
g_ed_command(X)
|
|||
|
|
|||
|
Instantiates X to the command presently used to call the editor.
|
|||
|
To call a different editor, assertz your own clause for this
|
|||
|
predicate (e.g., 'g_ed_command(emacs)').
|
|||
|
|
|||
|
|
|||
|
g_herald(X)
|
|||
|
|
|||
|
Instantiates X to an atom identifying the current version of
|
|||
|
GULP.
|
|||
|
|
|||
|
|
|||
|
A.7 Differences between GULP 1.1 and 2.0
|
|||
|
|
|||
|
(1) g_features declarations are no longer required, but are
|
|||
|
still permitted, and, if used, need not be complete.
|
|||
|
|
|||
|
(2) The operator '..' is now preferred in place of '::'. However,
|
|||
|
the older form can still be used.
|
|||
|
|
|||
|
(3) There have been minor changes in the operator precedence of
|
|||
|
':' and '..' relative to other operators. This is extremely
|
|||
|
unlikely to cause problems unless you have written feature
|
|||
|
structures that contain other operators such as '+' or '-'.
|
|||
|
|
|||
|
(4) GULP 2.0 distinguishes between features that are mentioned but
|
|||
|
uninstantiated, and features that are never mentioned. Previously,
|
|||
|
g_display never printed out any uninstantiated features.
|
|||
|
|
|||
|
(5) Bugs have been corrected. Translation of value lists to
|
|||
|
feature structures works correctly.
|
|||
|
|
|||
|
(6) Some rarely used built-in predicates have been deleted. In all
|
|||
|
cases these predicates had more common synonyms (ed rather than
|
|||
|
g_ed, list rather than g_list, etc.).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
40
|
|||
|
|
|||
|
(7) list translates feature structures into GULP notation before
|
|||
|
displaying them. (A debugger with the same capability is foreseen
|
|||
|
in the future.)
|
|||
|
|
|||
|
(8) Nested loads are now supported. That is, a file being loaded
|
|||
|
can contain a directive such as ':- load file2.' which will be
|
|||
|
executed correctly.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
41
|
|||
|
|
|||
|
Figure 1. A syntactic tree (based on Chomsky 1957).
|
|||
|
|
|||
|
|
|||
|
S
|
|||
|
|
|||
|
|
|||
|
NP VP
|
|||
|
|
|||
|
|
|||
|
D N V
|
|||
|
|
|||
|
|
|||
|
The dog barks.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
Figure 2. The same tree with features added.
|
|||
|
|
|||
|
|
|||
|
S
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NP VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> num:singular <20> <20> num:singular <20>
|
|||
|
<20> <20> <20> pers:3rd <20>
|
|||
|
<20> tense:present <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
|
|||
|
D N V
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> num:singular <20> <20> num:singular <20>
|
|||
|
<20> <20> <20> pers:3rd <20>
|
|||
|
<20> tense:present <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
The dog barks.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
42
|
|||
|
|
|||
|
Figure 3. An example of a unification-based grammar.
|
|||
|
|
|||
|
|
|||
|
[a] S --> NP VP
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:X <20> <20> <20> sem:Y <20> <20> sem:<3A> pred:X <20> <20>
|
|||
|
<20> <20> arg1:Y <20> <20> <20> case:nom <20> <20> <20> arg2:Z <20> <20>
|
|||
|
<20> <20> arg2:Z <20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
|
|||
|
|
|||
|
[b] VP --> V NP
|
|||
|
<20> <20> <20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:X1 <20> <20> <20> sem:X1 <20> <20> sem:Y1 <20>
|
|||
|
<20> <20> arg2:Y1 <20> <20> <20> <20> <20> case:acc <20>
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
|
|||
|
|
|||
|
[c] V --> sees
|
|||
|
[sem:SEES]
|
|||
|
|
|||
|
|
|||
|
[d] NP --> Max
|
|||
|
[sem:MAX]
|
|||
|
|
|||
|
|
|||
|
[e] NP --> Bill
|
|||
|
[sem:BILL]
|
|||
|
|
|||
|
|
|||
|
[f] NP --> me
|
|||
|
<20> <20>
|
|||
|
<20> sem:ME <20>
|
|||
|
<20> case:acc <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
43
|
|||
|
|
|||
|
Figure 4. Bottom-up parsing of Max sees Bill.
|
|||
|
|
|||
|
|
|||
|
a. Rules [c], [d], and [e] supply features for individual words:
|
|||
|
|
|||
|
NP V NP
|
|||
|
[sem:MAX] [sem:SEES] [sem:BILL]
|
|||
|
<20> <20> <20>
|
|||
|
Max sees Bill
|
|||
|
|
|||
|
|
|||
|
|
|||
|
b. Rule [b] allows V and NP to be grouped into a VP:
|
|||
|
|
|||
|
|
|||
|
VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:SEES <20> <20>
|
|||
|
<20> <20> arg2:BILL <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20>
|
|||
|
|
|||
|
|
|||
|
<20> <20>
|
|||
|
NP V NP
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:MAX <20> <20> sem:SEES <20> <20> sem:BILL <20>
|
|||
|
<20> <20> <20> <20> <20> case:acc <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> <20> <20>
|
|||
|
Max sees Bill
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
44
|
|||
|
|
|||
|
c. Rule [a] allows NP and VP to be grouped into an S:
|
|||
|
|
|||
|
|
|||
|
S
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:SEES <20> <20>
|
|||
|
<20> <20> arg1:MAX <20> <20>
|
|||
|
<20> <20> arg2:BILL <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20>
|
|||
|
|
|||
|
|
|||
|
<20>
|
|||
|
VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:SEES <20> <20>
|
|||
|
<20> <20> arg2:BILL <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20>
|
|||
|
|
|||
|
|
|||
|
<20> <20> <20>
|
|||
|
NP V NP
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:MAX <20> <20> sem:SEES <20> <20> sem:BILL <20>
|
|||
|
<20> case:nom <20> <20> <20> <20> case:acc <20>
|
|||
|
<20> <20> <20> <20> <20>
|
|||
|
<20> <20> <20>
|
|||
|
Max sees Bill
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
45
|
|||
|
|
|||
|
Figure 5. DAG representations of feature structures.
|
|||
|
|
|||
|
.
|
|||
|
|
|||
|
<20> <20>
|
|||
|
<20> a:b <20>
|
|||
|
<20> c:b <20> = a c e
|
|||
|
<20> e:d <20>
|
|||
|
<20> <20>
|
|||
|
|
|||
|
|
|||
|
b d
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
<20> <20> <20> <20> syn sem
|
|||
|
<20> syn:<3A> case:acc <20> <20>
|
|||
|
<20> <20> gender:masc <20> <20> =
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:MAN <20> .
|
|||
|
<20> <20>
|
|||
|
|
|||
|
case gender MAN
|
|||
|
|
|||
|
|
|||
|
acc masc
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
46
|
|||
|
|
|||
|
Figure 6. Parse tree for Max sees me. The ungrammatical sentence
|
|||
|
Me sees Max is ruled out by a feature conflict.
|
|||
|
|
|||
|
|
|||
|
S
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:SEES <20> <20>
|
|||
|
<20> <20> arg1:MAX <20> <20>
|
|||
|
<20> <20> arg2:ME <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20>
|
|||
|
|
|||
|
|
|||
|
<20>
|
|||
|
VP
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20> sem:<3A> pred:SEES <20> <20>
|
|||
|
<20> <20> arg2:ME <20> <20>
|
|||
|
<20> <20> <20> <20>
|
|||
|
<20>
|
|||
|
|
|||
|
|
|||
|
<20> <20> <20>
|
|||
|
NP V NP
|
|||
|
<20> <20> <20> <20> <20> <20>
|
|||
|
<20> sem:MAX <20> <20> sem:SEES <20> <20> sem:ME <20>
|
|||
|
<20> case:nom <20> <20> <20> <20> case:acc <20>
|
|||
|
<20> <20> <20> <20> <20>
|
|||
|
<20> <20> <20>
|
|||
|
Max sees me
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
47
|
|||
|
|
|||
|
Figure 7.
|
|||
|
|
|||
|
% GULP example 1.
|
|||
|
% Grammar from Figure 3, in DCG notation, with GULP feature structures.
|
|||
|
|
|||
|
s(sem: (pred:X .. arg1:Y .. arg2:Z)) --> np(sem:Y .. case:nom),
|
|||
|
vp(sem: (pred:X .. arg2:Z)).
|
|||
|
|
|||
|
vp(sem: (pred:X1 .. arg2:Y1)) --> v(sem:X1),
|
|||
|
np(sem:Y1).
|
|||
|
|
|||
|
v(sem:'SEES') --> [sees].
|
|||
|
|
|||
|
np(sem:'MAX') --> [max].
|
|||
|
|
|||
|
np(sem:'BILL') --> [bill].
|
|||
|
|
|||
|
np(sem:'ME' .. case:acc) --> [me].
|
|||
|
|
|||
|
|
|||
|
% Procedure to parse a sentence and display its features
|
|||
|
|
|||
|
try(String) :- writeln([String]),
|
|||
|
phrase(s(Features),String),
|
|||
|
display_feature_structure(Features).
|
|||
|
|
|||
|
|
|||
|
% Example sentences
|
|||
|
|
|||
|
test1 :- try([max,sees,bill]).
|
|||
|
test2 :- try([max,sees,me]).
|
|||
|
test3 :- try([me,sees,max]). /* should fail */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
48
|
|||
|
|
|||
|
Figure 8.
|
|||
|
|
|||
|
% Same as GULP example 1, but written in a much more PATR-like style,
|
|||
|
% treating the unifications as separate operations.
|
|||
|
|
|||
|
s(Sfeatures) --> np(NPfeatures), vp(VPfeatures),
|
|||
|
{ Sfeatures = sem: (pred:X .. arg1:Y .. arg2:Z),
|
|||
|
NPfeatures = sem:Y .. case:nom,
|
|||
|
VPfeatures = sem: (pred:X .. arg2:Z) }.
|
|||
|
|
|||
|
vp(VPfeatures) --> v(Vfeatures), np(NPfeatures),
|
|||
|
{ VPfeatures = sem: (pred:X1 .. arg2:Y1),
|
|||
|
Vfeatures = sem:X1,
|
|||
|
NPfeatures = sem:Y1 }.
|
|||
|
|
|||
|
v(Features) --> [sees], { Features = sem:'SEES' }.
|
|||
|
|
|||
|
np(Features) --> [max], { Features = sem:'MAX' }.
|
|||
|
|
|||
|
np(Features) --> [bill], { Features = sem:'BILL' }.
|
|||
|
|
|||
|
np(Features) --> [me], { Features = sem:'ME' .. case:acc }.
|
|||
|
|
|||
|
|
|||
|
% Procedure to parse a sentence and display its features
|
|||
|
|
|||
|
try(String) :- writeln([String]),
|
|||
|
s(Features,String,[]),
|
|||
|
display_feature_structure(Features).
|
|||
|
|
|||
|
|
|||
|
% Example sentences
|
|||
|
|
|||
|
test1 :- try([max,sees,bill]).
|
|||
|
test2 :- try([max,sees,me]).
|
|||
|
test3 :- try([me,sees,max]). /* should fail */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
49
|
|||
|
|
|||
|
Figure 9.
|
|||
|
|
|||
|
% Demonstration of a hold stack that
|
|||
|
% picks up the word 'what' at beginning of
|
|||
|
% sentence, and carries it along until an
|
|||
|
% empty NP position is found
|
|||
|
|
|||
|
% S may or may not begin with 'what did'.
|
|||
|
% In the latter case 'what' is added to the stack
|
|||
|
% before the NP and VP are parsed.
|
|||
|
|
|||
|
s(S) --> np(NP), vp(VP),
|
|||
|
{ S = hold: (in:H1..out:H3),
|
|||
|
NP = hold: (in:H1..out:H2),
|
|||
|
VP = hold: (in:H2..out:H3) }.
|
|||
|
|
|||
|
s(S) --> [what,did], np(NP), vp(VP),
|
|||
|
{ S = hold: (in:H1..out:H3),
|
|||
|
NP = hold: (in:[what|H1]..out:H2),
|
|||
|
VP = hold: (in:H2..out:H3) }.
|
|||
|
|
|||
|
% NP is parsed by either accepting det and n,
|
|||
|
% leaving the hold stack unchanged, or else
|
|||
|
% by extracting 'what' from the stack without
|
|||
|
% accepting anything from the input string.
|
|||
|
|
|||
|
np(NP) --> det, n, { NP = hold: (in:H..out:H) }.
|
|||
|
|
|||
|
np(NP) --> [], { NP = hold: (in:[what|H1]..out:H1) }.
|
|||
|
|
|||
|
|
|||
|
% VP consists of V followed by NP or S.
|
|||
|
% Both hold:in and hold:out are the same
|
|||
|
% on the VP as on the S or NP, since the
|
|||
|
% hold stack can only be altered while
|
|||
|
% processing the S or NP, not the verb.
|
|||
|
|
|||
|
vp(VP) --> v, np(NP), { VP = hold:H,
|
|||
|
NP = hold:H }.
|
|||
|
|
|||
|
vp(VP) --> v, s(S), { VP = hold:H,
|
|||
|
S = hold:H }.
|
|||
|
|
|||
|
% Lexicon
|
|||
|
|
|||
|
det --> [the];[a];[an].
|
|||
|
n --> [dog];[cat];[boy].
|
|||
|
v --> [said];[say];[chase];[chased].
|
|||
|
|
|||
|
try(X) :- writeln([X]),
|
|||
|
S = hold: (in:[]..out:[]),
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
50
|
|||
|
|
|||
|
phrase(s(S),X,[]).
|
|||
|
|
|||
|
test1 :- try([the,boy,said,the,dog,chased,the,cat]).
|
|||
|
test2 :- try([what,did,the,boy,say,chased,the,cat]).
|
|||
|
test3 :- try([what,did,the,boy,say,the,cat,chased]).
|
|||
|
test4 :- try([what,did,the,boy,say,the,dog,chased,the,cat]).
|
|||
|
/* test4 should fail */
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
51
|
|||
|
|
|||
|
Figure 10.
|
|||
|
|
|||
|
% Discourse Representation Theory
|
|||
|
% (part of the program from Johnson & Klein 1986,
|
|||
|
% translated from PrAtt into GULP).
|
|||
|
|
|||
|
|
|||
|
% unique_integer(N)
|
|||
|
% instantiates N to a different integer
|
|||
|
% every time it is called, thereby generating
|
|||
|
% unique indices.
|
|||
|
|
|||
|
|
|||
|
unique_integer(N) :-
|
|||
|
retract(unique_aux(N)),
|
|||
|
!,
|
|||
|
NewN is N+1,
|
|||
|
asserta(unique_aux(NewN)).
|
|||
|
|
|||
|
unique_aux(0).
|
|||
|
|
|||
|
|
|||
|
% Nouns
|
|||
|
% Each noun generates a unique index and inserts
|
|||
|
% it, along with a condition, into the DRS that
|
|||
|
% is passed to it.
|
|||
|
|
|||
|
|
|||
|
n(N) --> [man],
|
|||
|
{ unique_integer(C),
|
|||
|
N = syn:index:C ..
|
|||
|
sem: (in: [Current|Super] ..
|
|||
|
out: [[C,man(C)|Current]|Super]) }.
|
|||
|
|
|||
|
n(N) --> [donkey],
|
|||
|
{ unique_integer(C),
|
|||
|
N = syn:index:C ..
|
|||
|
sem: (in: [Current|Super] ..
|
|||
|
out: [[C,donkey(C)|Current]|Super]) }.
|
|||
|
|
|||
|
% Verbs
|
|||
|
% Each verb is linked to the indices of its arguments
|
|||
|
% through syntactic features. Using these indices,
|
|||
|
% it adds the appropriate predicate to the semantics.
|
|||
|
|
|||
|
v(V) --> [saw],
|
|||
|
{ V = syn: (arg1:Arg1 .. arg2:Arg2) ..
|
|||
|
sem: (in: [Current|Super] ..
|
|||
|
out: [[saw(Arg1,Arg2)|Current]|Super]) }.
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
52
|
|||
|
|
|||
|
% Determiners
|
|||
|
% Determiners tie together the semantics of their
|
|||
|
% scope and restrictor. The simplest determiner,
|
|||
|
% 'a', simply passes semantic material to its
|
|||
|
% restrictor and then to its scope. A more complex
|
|||
|
% determiner such as 'every' passes an empty list
|
|||
|
% to its scope and restrictor, collects whatever
|
|||
|
% semantic material they add, and then arranges
|
|||
|
% it into an if-then structure.
|
|||
|
|
|||
|
det(Det) --> [a],
|
|||
|
{ Det = sem:res:in:A, Det = sem:in:A,
|
|||
|
Det = sem:scope:in:B, Det = sem:res:out:B,
|
|||
|
Det = sem:out:C, Det = sem:scope:out:C }.
|
|||
|
|
|||
|
det(Det) --> [every],
|
|||
|
{ Det = sem:res:in:[[]|A], Det = sem:in:A,
|
|||
|
Det = sem:scope:in:[[]|B], Det = sem:res:out:B,
|
|||
|
Det = sem:scope:out:[Scope,Res|[Current|Super]],
|
|||
|
Det = sem:out:[[Res>Scope|Current]|Super] }.
|
|||
|
|
|||
|
|
|||
|
% Noun phrase
|
|||
|
% Pass semantic material to the determiner, which
|
|||
|
% will specify the logical structure.
|
|||
|
|
|||
|
np(NP) --> { NP=sem:A, Det=sem:A,
|
|||
|
Det=sem:res:B, N=sem:B,
|
|||
|
NP=syn:C, N=syn:C }, det(Det),n(N).
|
|||
|
|
|||
|
% Verb phrase
|
|||
|
% Pass semantic material to the embedded NP
|
|||
|
% (the direct object).
|
|||
|
|
|||
|
vp(VP) --> { VP = sem:A, NP = sem:A,
|
|||
|
NP = sem:scope:B, V = sem:B,
|
|||
|
VP = syn:arg2:C, NP = syn:index:C,
|
|||
|
VP = syn:D, V = syn:D }, v(V), np(NP).
|
|||
|
|
|||
|
% Sentence
|
|||
|
% Pass semantic material to the subject NP.
|
|||
|
% Pass VP semantics to the subject NP as its scope.
|
|||
|
|
|||
|
s(S) --> { S = sem:A, NP = sem:A,
|
|||
|
S = syn:B, VP = syn:B,
|
|||
|
NP = sem:scope:C, VP = sem:C,
|
|||
|
VP = syn:arg1:D, NP = syn:index:D }, np(NP), vp(VP).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
% Procedure to parse and display a sentence
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
53
|
|||
|
|
|||
|
try(String) :- write(String),nl,
|
|||
|
Features = sem:in:[[]], /* start w. empty structure */
|
|||
|
phrase(s(Features),String),
|
|||
|
Features = sem:out:SemOut, /* extract what was built */
|
|||
|
display_feature_structure(SemOut).
|
|||
|
|
|||
|
% Example sentences
|
|||
|
|
|||
|
test1 :- try([a,man,saw,a,donkey]).
|
|||
|
test2 :- try([a,donkey,saw,a,man]).
|
|||
|
test3 :- try([every,man,saw,a,donkey]).
|
|||
|
test4 :- try([every,man,saw,every,donkey]).
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
54
|
|||
|
|
|||
|
Figure 11.
|
|||
|
|
|||
|
% BUP in GULP:
|
|||
|
% Bottom-up parsing algorithm of Matsumoto et al. (1986)
|
|||
|
% with the grammar from Figure 3.
|
|||
|
|
|||
|
|
|||
|
% Goal-forming clause
|
|||
|
|
|||
|
goal(G,Gf,S1,S3) :-
|
|||
|
word(W,Wf,S1,S2),
|
|||
|
NewGoal =.. [W,G,Wf,Gf,S2,S3],
|
|||
|
call(NewGoal).
|
|||
|
|
|||
|
|
|||
|
% Terminal clauses for nonterminal symbols
|
|||
|
|
|||
|
s(s,F,F,X,X).
|
|||
|
vp(vp,F,F,X,X).
|
|||
|
np(np,F,F,X,X).
|
|||
|
|
|||
|
|
|||
|
% Phrase-structure rules
|
|||
|
|
|||
|
% np vp --> s
|
|||
|
|
|||
|
np(G,NPf,Gf,S1,S3) :- goal(vp,VPf,S1,S2),
|
|||
|
s(G,Sf,Gf,S2,S3),
|
|||
|
NPf = sem:Y..case:nom,
|
|||
|
VPf = sem: (pred:X..arg2:Z),
|
|||
|
Sf = sem: (pred:X..arg1:Y..arg2:Z).
|
|||
|
|
|||
|
|
|||
|
% v np --> vp
|
|||
|
|
|||
|
v(G,Vf,Gf,S1,S3) :- goal(np,NPf,S1,S2),
|
|||
|
vp(G,VPf,Gf,S2,S3),
|
|||
|
Vf = sem:X1,
|
|||
|
NPf = sem:Y1..case:acc,
|
|||
|
VPf = sem: (pred:X1..arg2:Y1).
|
|||
|
|
|||
|
|
|||
|
% Terminal symbols
|
|||
|
|
|||
|
word(v,sem:'SEES',[sees|X],X).
|
|||
|
word(np,sem:'MAX',[max|X],X).
|
|||
|
word(np,sem:'BILL',[bill|X],X).
|
|||
|
word(np,sem:'ME'..case:acc,[me|X],X).
|
|||
|
|
|||
|
|
|||
|
% Procedure to parse a sentence and display its features
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
55
|
|||
|
|
|||
|
try(String) :- writeln([String]),
|
|||
|
goal(s,Features,String,[]),
|
|||
|
display_feature_structure(Features).
|
|||
|
|
|||
|
|
|||
|
% Example sentences
|
|||
|
|
|||
|
test1 :- try([max,sees,bill]).
|
|||
|
test2 :- try([max,sees,me]).
|
|||
|
test3 :- try([me,sees,max]). /* should fail */
|
|||
|
|