【问题标题】:Sentence parsing and matching in PrologProlog中的句子解析和匹配
【发布时间】:2017-12-07 20:39:32
【问题描述】:

我正在尝试在 Prolog 中创建一个句子解析器。我希望将句子解析为三个单独的列表,这些列表将与建议的结果相匹配。

例如,这里是我到目前为止想出的代码...


这是用于解析某些单词的词汇表:

det(the).
det(a).
det(an).
noun(cat).
noun(boy).
noun(girl).
noun(grandfather).
noun(person).
noun(mat).
noun(party).
noun(book).
noun(problem).
noun(father).
noun(student).
noun(golf).
noun(conversation).
noun(challenge).
noun(person).
noun(problem).
noun(sat).
verb(thrives).
verb(loves).
verb(likes).
prep(on).
prep(with).
adj(big).
adj(lonely).
adj(elderly).
adj(teenage).
adj(good).
adj(fat).

sentence(Sentence,sentence(Noun_Phrase,Verb_Phrase)):-
      np(Sentence,Noun_Phrase,Rem),
      vp(Rem,Verb_Phrase).

解析代码:

np([X|T],np(det(X),NP2),Rem):- /* Det NP2 */
    det(X),
    np2(T,NP2,Rem).
np(Sentence,Parse,Rem):- np2(Sentence,Parse,Rem). /* NP2 */
np(Sentence,np(NP,PP),Rem):- /* NP PP */
    np(Sentence,NP,Rem1),
    pp(Rem1,PP,Rem).

np2([H|T],np2(noun(H)),T):- noun(H). /* Noun */
np2([H|T],np2(adj(H),Rest),Rem):- adj(H),np2(T,Rest,Rem).

pp([H|T],pp(prep(H),Parse),Rem):- /* PP NP */
    prep(H),
    np(T,Parse,Rem).

vp([H| []], vp(verb(H))):- /* Verb */
    verb(H).

vp([H|T], vp(verb(H), Rem)):- /* VP PP */
    vp(H, Rem),
    pp(T, Rem, _).

vp([H|T], vp(verb(H), Rem)):- /* Verb NP */
    verb(H),
    np(T, Rem, _).

然后我想用这样的东西从中获取输出......

?- sentence([a,very,young,boy,loves,a,manual,problem],Parse).

然后不知何故根据这样的事实提出礼物......

present(construction_kit, subject(very,young,boy), verb(loves), object(manual,problem)).
present(a_golfing_sweater, subject(young,father), verb(loves), object(golf)).

如您所见,我希望将其与现有的“construction_kit”相匹配。

【问题讨论】:

  • 您没有使用 DCG 的任何原因?
  • Tomas 要问的是为什么你不使用 DCG 来实现你的语法。 DCG 使其更加透明。 例如sentence --> noun_phrase, verb_phrase.
  • 请参阅this 如何使用 DCG 编写此内容。 (DCG 正是 Prolog 存在的原因!)
  • 这里的问题与你的整个方法有关,它不会扩展,而不是你的具体问题。我强烈建议您查看 Ivan Bratko 的书 Prolog Programming for AI 或 Pereira 的书 Prolog 和自然语言分析,它们都通过解析为 lambda 来满足更复杂的查询微积分表达式,然后计算它们。
  • @TomasBy DCG 是从哪里开始的,但我们在这里有一个巨大的解决方案空间和一个非常未指定的问题。顺便说一句,这本书的年代与质量或重要性无关,尤其是在 Prolog 中几乎没有什么变化。

标签: list prolog dcg


【解决方案1】:

让我们尝试将其精简为一个小问题,以便我们了解如何解决它。让我们从更简单的语法开始。

sentence(NP, VP) --> noun_phrase(NP), verb_phrase(VP).
noun_phrase(np(Noun, Adj)) --> det, adjectives(Adj), noun(Noun).

det --> [D], { det(D) }.
det --> [].

noun(N) --> [N], { noun(N) }.

adjectives([]) --> [].
adjectives([A|As]) --> adjective(A), adjectives(As).
adjective(A) --> [A], { adj(A) }.

verb_phrase(vp(Verb, Noun)) --> verb(Verb), noun_phrase(Noun).

verb(V) --> [V], { verb(V) }.

即使对于你的问题,这也不是一个完整的语法,但它会解析一些句子:

?- phrase(sentence(NP,VP), [a,teenage,boy,loves,a,big,problem]).
NP = np(boy, [teenage]),
VP = vp(loves, np(problem, [big])) 

现在我们可以制作一个现在的数据库。我现在只考虑名词短语的“头部”。

present('construction kit', boy, loves, problem).

现在您可以部署一个非常简单的查询来尝试匹配它们:

?- phrase(sentence(np(Noun,_), vp(Verb, np(Object, _))),
   [a,teenage,boy,loves,a,big,problem]), 
   present(Suggestion, Noun, Verb, Object).
Noun = boy,
Verb = loves,
Object = problem,
Suggestion = 'construction kit' ;

现在您可以立即看到您最大的问题:如果您尝试匹配更复杂的语法,您将不得不相应增加查询的复杂性,这会将其转化为建议。这类问题的解决方案(其中两件事似乎同时增加了复杂性)总是在它们之间创建一个抽象,但这超出了这个问题的范围。

编辑 值得注意的是,如果你想建立一个通用的推荐系统,这不是一个现代的方法。我推荐Programming Collective Intelligence一书,以快速了解几种方法,并以可读性强的 Python 为后盾。

编辑是否清楚,使语法更复杂会导致匹配呈现的更复杂?

首先,我完全省略了你的介词短语产生。我只是没有包括那个。如果它在那里,它会影响这个建议吗?考虑像“一个喜欢编程的少年喜欢一个大问题”这样的句子——我的noun_phrase//1 的自然延伸来涵盖这个案例会错过这个孩子的一个重要细节,这可能会让你看到一个不同于构造集。

假设您要处理该补充信息,您将不得不在phrase/3 的第一个参数中添加更多模式。事实上,你可能会接受任何出现的内容,然后发送到某种建议系统。

@TomasBy 做得对的一点是,我们在这里使用了一个非常简单的中间表示,即(名词、动词、宾语)。但是如果我们让语法更复杂,我们将不得不在这个表示中捕获和处理更多的语法,这将提高建议系统的复杂性。例如,我不知道如何扩展这个简单的表示来处理介词短语,除非你把它们扔掉。

将 DCG 转换回普通 Prolog

这很简单,但 Prolog 会为您完成。您可以简单地加载上面的 DCG 并使用listing/0 来获得答案。

| ?- listing.

% file: user

sentence(A, B, C, D) :-
    noun_phrase(A, C, E),
    verb_phrase(B, E, D).

noun_phrase(np(A, B), C, D) :-
    det(C, E),
    adjectives(B, E, F),
    noun(A, F, D).

det([A|B], C) :-
    det(A),
    B = C.
det(A, A).

noun(A, [A|B], C) :-
    noun(A),
    B = C.

adjectives([], A, A).
adjectives([A|B], C, D) :-
    adjective(A, C, E),
    adjectives(B, E, D).

adjective(A, [A|B], C) :-
    adj(A),
    B = C.

verb_phrase(vp(A, B), C, D) :-
    verb(A, C, E),
    noun_phrase(B, E, D).

verb(A, [A|B], C) :-
    verb(A),
    B = C.

【讨论】:

  • 更复杂的语法必然导致更复杂的中间表示是不正确的。解析器可以为一个输入生成多个单独的表示,或者它可以只是扔掉一些东西,这可能适用于例如状语。
  • 有什么方法可以将顶部的 DSG 更改为我使用的格式吗?只是我暂时不明白。我会理解它,但目前我所有的代码都是以我提出问题的格式编写的。谢谢。
  • 接受这个答案并提出另一个问题,当然。
猜你喜欢
  • 1970-01-01
  • 2012-06-28
  • 2012-04-01
  • 1970-01-01
  • 2018-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多