4.3 量化的 NP

在本节开始,我们简要介绍了如何为 Cyril barks 构建语义表示。你会以为这太容易了——肯定还有更多关于建立组合语义的。例如,量词?没错,这是一个至关重要的问题。例如,我们要给出(42a)的逻辑形式(42b)。如何才能实现呢?

  1. >>> read_expr = nltk.sem.Expression.fromstring
  2. >>> tvp = read_expr(r'\X x.X(\y.chase(x,y))')
  3. >>> np = read_expr(r'(\P.exists x.(dog(x) & P(x)))')
  4. >>> vp = nltk.sem.ApplicationExpression(tvp, np)
  5. >>> print(vp)
  6. (\X x.X(\y.chase(x,y)))(\P.exists x.(dog(x) & P(x)))
  7. >>> print(vp.simplify())
  8. \x.exists z2.(dog(z2) & chase(x,z2))

为了建立一个句子的语义表示,我们也需要组合主语NP的语义。如果后者是一个量化的表达式,例如 every girl,一切都与我们前面讲过的 a dog barks 一样的处理方式;主语转换为函数表达式,这被用于VP的语义表示。然而,我们现在似乎已经用适当的名称为自己创造了另一个问题。到目前为止,这些已经作为单独的常量进行了语义的处理,这些不能作为像(47)那样的表达式的函数应用。因此,我们需要为它们提出不同的语义表示。我们在这种情况下所做的是重新解释适当的名称,使它们也成为如量化的NP那样的函数表达式。这里是 Angus 的λ表达式。

  1. >>> from nltk import load_parser
  2. >>> parser = load_parser('grammars/book_grammars/simple-sem.fcfg', trace=0)
  3. >>> sentence = 'Angus gives a bone to every dog'
  4. >>> tokens = sentence.split()
  5. >>> for tree in parser.parse(tokens):
  6. ... print(tree.label()['SEM'])
  7. all z2.(dog(z2) -> exists z1.(bone(z1) & give(angus,z1,z2)))

NLTK 提供一些实用工具使获得和检查的语义解释更容易。函数interpret_sents()用于批量解释输入句子的列表。它建立一个字典d,其中对每个输入的句子sentd[sent]是包含sent的分析树和语义表示的(synrep, semrep)对的列表。该值是一个列表,因为sent可能有句法歧义;在下面的例子中,列表中的每个句子只有一个分析树。

  1. >>> sents = ['Irene walks', 'Cyril bites an ankle']
  2. >>> grammar_file = 'grammars/book_grammars/simple-sem.fcfg'
  3. >>> for results in nltk.interpret_sents(sents, grammar_file):
  4. ... for (synrep, semrep) in results:
  5. ... print(synrep)
  6. (S[SEM=<walk(irene)>]
  7. (NP[-LOC, NUM='sg', SEM=<\P.P(irene)>]
  8. (PropN[-LOC, NUM='sg', SEM=<\P.P(irene)>] Irene))
  9. (VP[NUM='sg', SEM=<\x.walk(x)>]
  10. (IV[NUM='sg', SEM=<\x.walk(x)>, TNS='pres'] walks)))
  11. (S[SEM=<exists z3.(ankle(z3) & bite(cyril,z3))>]
  12. (NP[-LOC, NUM='sg', SEM=<\P.P(cyril)>]
  13. (PropN[-LOC, NUM='sg', SEM=<\P.P(cyril)>] Cyril))
  14. (VP[NUM='sg', SEM=<\x.exists z3.(ankle(z3) & bite(x,z3))>]
  15. (TV[NUM='sg', SEM=<\X x.X(\y.bite(x,y))>, TNS='pres'] bites)
  16. (NP[NUM='sg', SEM=<\Q.exists x.(ankle(x) & Q(x))>]
  17. (Det[NUM='sg', SEM=<\P Q.exists x.(P(x) & Q(x))>] an)
  18. (Nom[NUM='sg', SEM=<\x.ankle(x)>]
  19. (N[NUM='sg', SEM=<\x.ankle(x)>] ankle)))))

现在我们已经看到了英文句子如何转换成逻辑形式,前面我们看到了在模型中如何检查逻辑形式的真假。把这两个映射放在一起,我们可以检查一个给定的模型中的英语句子的真值。让我们看看前面定义的模型m。工具evaluate_sents()类似于interpret_sents(),除了我们需要传递一个模型和一个变量赋值作为参数。输出是三元组(synrep, semrep, value),其中 synrepsemrep 和以前一样,value 是真值。为简单起见,下面的例子只处理一个简单的句子。

  1. >>> v = """
  2. ... bertie => b
  3. ... olive => o
  4. ... cyril => c
  5. ... boy => {b}
  6. ... girl => {o}
  7. ... dog => {c}
  8. ... walk => {o, c}
  9. ... see => {(b, o), (c, b), (o, c)}
  10. ... """
  11. >>> val = nltk.Valuation.fromstring(v)
  12. >>> g = nltk.Assignment(val.domain)
  13. >>> m = nltk.Model(val.domain, val)
  14. >>> sent = 'Cyril sees every boy'
  15. >>> grammar_file = 'grammars/book_grammars/simple-sem.fcfg'
  16. >>> results = nltk.evaluate_sents([sent], grammar_file, m, g)[0]
  17. >>> for (syntree, semrep, value) in results:
  18. ... print(semrep)
  19. ... print(value)
  20. all z4.(boy(z4) -> see(cyril,z4))
  21. True