我有一个句子及其语法,在哪里可以找到允许我用逻辑语言编写句子的谓词序言?
存在或任何人可以帮助我创建一个
的谓词将以下字符串
作为输入(S (NP (NNP John))
(VP (VBP see)
(NP (NNP Mary))))
并返回此
see(John,Mary)
答案 0 :(得分:1)
如果我理解,你需要解析LISP结构到Prolog。然后由Markus Triska撰写的LisProlog可能是合适的工具。使用该片段和此片段
test :- parse("(S (NP (NNP John))
(VP (VBP see)
(NP (NNP Mary))))",
R),
maplist(sexp_write(""), R).
sexp_write(Indent, E) :-
is_list(E),
format('~s~w~n', [Indent, E]),
maplist(sexp_write([0' |Indent]), E).
sexp_write(Indent, E) :-
format('~s~w~n', [Indent, E]).
我得到了
?- test.
[s(S),[s(NP),[s(NNP),s(John)]],[s(VP),[s(VBP),s(see)],[s(NP),[s(NNP),s(Mary)]]]]
s(S)
[s(NP),[s(NNP),s(John)]]
s(NP)
[s(NNP),s(John)]
s(NNP)
s(John)
[s(VP),[s(VBP),s(see)],[s(NP),[s(NNP),s(Mary)]]]
s(VP)
[s(VBP),s(see)]
s(VBP)
s(see)
[s(NP),[s(NNP),s(Mary)]]
s(NP)
[s(NNP),s(Mary)]
s(NNP)
s(Mary)
true .
现在您应该决定将逻辑表单翻译成Prolog术语。
一般来说,这是一个困难的主题,因为你需要做一些关于量化的选择。对于您的简单陈述,您可以从非常简单的模式匹配开始,完全忽略上述问题。
sexp_to_term(S_exp, T_exp) :-
parse(S_exp, [R]),
termize(R, T),
pattern(T, T_exp).
pattern(T, T_exp) :-
T = 'S'('NP'('NNP'(Subj)),'VP'('VBP'(Verb),'NP'('NNP'(Obj)))),
T_exp =.. [Verb, Subj, Obj].
termize(s(Tag), Tag).
termize([s(Tag)|Args], Term) :-
maplist(termize, Args, ArgsT),
Term =.. [Tag|ArgsT].
试验:
?- gtrace,sexp_to_term("(S (NP (NNP John)) (VP (VBP see) (NP (NNP Mary))))", T).
T = see('John', 'Mary').
答案 1 :(得分:1)
我认为@ CapelliC的答案更好(+1),但我想对它进行一次破解,看看我想出了什么。你可以在没有LisProlog的情况下解决这个问题,但你可以肯定LisProlog会比我的袖手旁观的DCG垃圾更好地完成 更好的工作。
首先,为了方便起见,我想将你的例句坚持到代码中,所以我不必继续重新输入代码:
sent("(S (NP (NNP John))
(VP (VBP see)
(NP (NNP Mary))))").
现在有一些帮助DCG规则:
whitespace --> [X], { char_type(X, white) ; char_type(X, space) }, whitespace.
whitespace --> [].
char(C) --> [C], { char_type(C, graph), \+ memberchk(C, "()") }.
我需要memberchk
来确保我不将括号放入原子中。
chars([C|Rest]) --> char(C), chars(Rest).
chars([C]) --> char(C).
term(T) --> chars(C), { atom_chars(T, C) }.
term(L) --> list(L).
list(T) --> "(", terms(T), ")".
terms([]) --> [].
terms([T|Terms]) --> term(T), whitespace, !, terms(Terms).
术语和列表之间存在相互递归,但这是我们想要的,因为我们希望列表能够嵌套在任何地方。我们来测试一下解析:
?- sent(X), phrase(list(Y), X).
X = [40, 83, 32, 40, 78, 80, 32, 40, 78|...],
Y = ['S', ['NP', ['NNP', 'John']], ['VP', ['VBP', see], ['NP', ['NNP'|...]]]] ;
到目前为止这看起来不错。模式匹配看起来与@ CapelliC非常相似:
simplify(['S', ['NP', ['NNP', Subject]],
['VP', ['VBP', Verb],
['NP', ['NNP', Object]]]],
Result) :-
Result =.. [Verb, Subject, Object].
不幸的是,使用大写原子掩盖了这里的意图,这实际上很自然。如果我们可以使用小写字母,那么模式将更像是这样:
simplify([s, [np, [nnp, Subject]],
[vp, [vbp, Verb],
[np, [nnp, Object]]]],
Result) :-
Result =.. [Verb, Subject, Object].
我们在这里使用强大的“univ”运算符(=..
)从列表中生成Prolog术语。您可以将此运算符视为Lisp转换器,因为它基本上就是它的作用:
?- s(this, that) =.. X.
X = [s, this, that].
?- X =.. [s, this, that].
X = s(this, that).
因此应该清楚模式匹配是如何工作的。让我们看看整个事物如何融合在一起:
?- sent(X), phrase(list(Y), X), simplify(Y, Z).
X = [40, 83, 32, 40, 78, 80, 32, 40, 78|...],
Y = ['S', ['NP', ['NNP', 'John']], ['VP', ['VBP', see], ['NP', ['NNP'|...]]]],
Z = see('John', 'Mary') .
对于它的价值,将自然语言句子翻译成逻辑命题是一个很大的问题。它通常不会那么容易,但有些书籍讨论如何解决问题。我建议查看自然语言的表示和推理,了解有关这个大问题的更多信息。
所以你有它。像这样手动操作的好处是你可以控制你想要采用的Lisp语法,并且它很容易扩展或修改。缺点是你必须调试语法 - 而且我很确定这个我没有注意到或者需要时间找到的问题(我远离DCG专家!)。如果没有更好的要求,我肯定会接受@ CapelliC的回答,但我认为看看如何从头开始接触它可能会有所帮助。