我试图在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'相匹配。本。
答案 0 :(得分:3)
让我们尝试将其减少到一个小问题,以便我们可以看到我们如何接近它。让我们从更简单的语法开始。
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]))
现在我们可以创建一个现有的数据库。我只是考虑一下" head"现在的名词短语。
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为后盾。
编辑很明显,使语法更复杂会导致匹配礼物更加复杂吗?
首先,我完全省略了你的介词短语制作。我只是没有把它包括在内。如果它在那里,它是否会影响该建议?考虑一个喜欢&#34的句子;一个喜欢编码的十几岁的男孩喜欢一个大问题"我noun_phrase//1
的自然延伸来涵盖这个案例将错过这个孩子的一个重要细节,可能会导致你到了与建筑集不同的礼物。
假设您要处理补充信息,则必须在phrase/3
的第一个参数中添加更多模式。事实上,你可能接受任何出来然后发送到某种建议系统。
@TomasBy正确的一件事是我们在这里使用一个非常简单的中间表示,它只是(名词,动词,对象)。但是如果我们使语法更复杂,我们将不得不在这种表示中捕获和处理更多的语法,这将提高建议系统的复杂性。我没有看到如何扩展这个简单的表示来处理介词短语,例如,除非你把它们扔掉。
这很简单,但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.