4.3 量化的 NP
在本节开始,我们简要介绍了如何为 Cyril barks 构建语义表示。你会以为这太容易了——肯定还有更多关于建立组合语义的。例如,量词?没错,这是一个至关重要的问题。例如,我们要给出(42a)的逻辑形式(42b)。如何才能实现呢?
>>> read_expr = nltk.sem.Expression.fromstring
>>> tvp = read_expr(r'\X x.X(\y.chase(x,y))')
>>> np = read_expr(r'(\P.exists x.(dog(x) & P(x)))')
>>> vp = nltk.sem.ApplicationExpression(tvp, np)
>>> print(vp)
(\X x.X(\y.chase(x,y)))(\P.exists x.(dog(x) & P(x)))
>>> print(vp.simplify())
\x.exists z2.(dog(z2) & chase(x,z2))
为了建立一个句子的语义表示,我们也需要组合主语NP
的语义。如果后者是一个量化的表达式,例如 every girl,一切都与我们前面讲过的 a dog barks 一样的处理方式;主语转换为函数表达式,这被用于VP
的语义表示。然而,我们现在似乎已经用适当的名称为自己创造了另一个问题。到目前为止,这些已经作为单独的常量进行了语义的处理,这些不能作为像(47)那样的表达式的函数应用。因此,我们需要为它们提出不同的语义表示。我们在这种情况下所做的是重新解释适当的名称,使它们也成为如量化的NP
那样的函数表达式。这里是 Angus 的λ表达式。
>>> from nltk import load_parser
>>> parser = load_parser('grammars/book_grammars/simple-sem.fcfg', trace=0)
>>> sentence = 'Angus gives a bone to every dog'
>>> tokens = sentence.split()
>>> for tree in parser.parse(tokens):
... print(tree.label()['SEM'])
all z2.(dog(z2) -> exists z1.(bone(z1) & give(angus,z1,z2)))
NLTK 提供一些实用工具使获得和检查的语义解释更容易。函数interpret_sents()
用于批量解释输入句子的列表。它建立一个字典d
,其中对每个输入的句子sent
,d[sent]
是包含sent
的分析树和语义表示的(synrep, semrep)对的列表。该值是一个列表,因为sent
可能有句法歧义;在下面的例子中,列表中的每个句子只有一个分析树。
>>> sents = ['Irene walks', 'Cyril bites an ankle']
>>> grammar_file = 'grammars/book_grammars/simple-sem.fcfg'
>>> for results in nltk.interpret_sents(sents, grammar_file):
... for (synrep, semrep) in results:
... print(synrep)
(S[SEM=<walk(irene)>]
(NP[-LOC, NUM='sg', SEM=<\P.P(irene)>]
(PropN[-LOC, NUM='sg', SEM=<\P.P(irene)>] Irene))
(VP[NUM='sg', SEM=<\x.walk(x)>]
(IV[NUM='sg', SEM=<\x.walk(x)>, TNS='pres'] walks)))
(S[SEM=<exists z3.(ankle(z3) & bite(cyril,z3))>]
(NP[-LOC, NUM='sg', SEM=<\P.P(cyril)>]
(PropN[-LOC, NUM='sg', SEM=<\P.P(cyril)>] Cyril))
(VP[NUM='sg', SEM=<\x.exists z3.(ankle(z3) & bite(x,z3))>]
(TV[NUM='sg', SEM=<\X x.X(\y.bite(x,y))>, TNS='pres'] bites)
(NP[NUM='sg', SEM=<\Q.exists x.(ankle(x) & Q(x))>]
(Det[NUM='sg', SEM=<\P Q.exists x.(P(x) & Q(x))>] an)
(Nom[NUM='sg', SEM=<\x.ankle(x)>]
(N[NUM='sg', SEM=<\x.ankle(x)>] ankle)))))
现在我们已经看到了英文句子如何转换成逻辑形式,前面我们看到了在模型中如何检查逻辑形式的真假。把这两个映射放在一起,我们可以检查一个给定的模型中的英语句子的真值。让我们看看前面定义的模型m
。工具evaluate_sents()
类似于interpret_sents()
,除了我们需要传递一个模型和一个变量赋值作为参数。输出是三元组(synrep, semrep, value),其中 synrep、semrep 和以前一样,value 是真值。为简单起见,下面的例子只处理一个简单的句子。
>>> v = """
... bertie => b
... olive => o
... cyril => c
... boy => {b}
... girl => {o}
... dog => {c}
... walk => {o, c}
... see => {(b, o), (c, b), (o, c)}
... """
>>> val = nltk.Valuation.fromstring(v)
>>> g = nltk.Assignment(val.domain)
>>> m = nltk.Model(val.domain, val)
>>> sent = 'Cyril sees every boy'
>>> grammar_file = 'grammars/book_grammars/simple-sem.fcfg'
>>> results = nltk.evaluate_sents([sent], grammar_file, m, g)[0]
>>> for (syntree, semrep, value) in results:
... print(semrep)
... print(value)
all z4.(boy(z4) -> see(cyril,z4))
True