如何使用prolog翻译逻辑语言中的句子?

时间:2013-02-19 09:24:58

标签: prolog

我有一个句子及其语法,在哪里可以找到允许我用逻辑语言编写句子的谓词序言?

存在或任何人可以帮助我创建一个

的谓词

将以下字符串

作为输入
(S (NP (NNP John))
    (VP (VBP see)
      (NP (NNP Mary))))

并返回此

see(John,Mary)

2 个答案:

答案 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的回答,但我认为看看如何从头开始接触它可能会有所帮助。