英语约束免费语法序言

时间:2013-03-27 20:02:05

标签: prolog infinite-loop dcg left-recursion failure-slice

我尝试在prolog中实现一个非常简单的约束自由语法时遇到了无限递归问题。

这是我的规则:(vp - >动词短语,np - >名词短语,ap - > adj短语,pp - >预备短语)

    verb(S) :- member(S, [put,  pickup, stack, unstack]).
    det(S) :- member(S, [the]).
    adj(S) :- member(S, [big, small, green, red, yellow, blue]).
    noun(S) :- member(S, [block, table]).
    prep(S) :- member(S, [on, from]).

    vp([V|R]) :- verb(V), pp(PP), np(NP), append(NP, PP, R).
    np([D, N]) :- det(D), noun(N).
    np([D|R]) :- det(D), ap(AP), noun(N), append(AP, [N], R).
    ap([A]) :- adj(A).
    ap([A|R]) :- adj(A), ap(R).
    pp([P|R]) :- prep(P), np(R).

我遇到的问题是 ap 的规则会产生任意长的形容词串,所以在某些时候,我试图通过尝试所有这些无限的可能性来试图满足查询。

例如,以下查询将永远不会产生S = [put,the,red,block,on,the,green,block],因为它将首先将左侧“红色”上的形容词短语扩展为无限可能性尝试在右边。

?- vp(S)
S = [put, the, red, green, block, on, the, block] ;

3 个答案:

答案 0 :(得分:5)

简短的回答是:使用Definite Clause Grammars()来表示你的语法。有关典型编码,请参阅this answer

但是现在你的程序中存在实际问题。你不仅得不到想要的答案;情况更糟:即使在一个更简单的程序片段中,你也会遇到同样的问题。这是程序中仍然没有终止的最小片段:

verb(S) :- member(S, [put,  pickup, stack, unstack]).
det(S) :- member(S, [the]).
adj(S) :- member(S, [big, small, green, red, yellow, blue]).
noun(S) :- false, member(S, [block, table]).
prep(S) :- member(S, [on, from]).

vp([V|R]) :- verb(V), pp(PP), false, np(NP), append(NP, PP, R).
np([D, N]) :- false, det(D), noun(N).
np([D|R]) :- det(D), ap(AP), false, noun(N), append(AP, [N], R).
ap([A]) :- false, adj(A).
ap([A|R]) :- adj(A), ap(R), false.
pp([P|R]) :- prep(P), np(R), false.

?- vp([put, the, red, green, block, on, the, block]).

通过插入目标 false ,我们得到了一个仍未终止的程序的小片段。 实际的源是ap/1,它是递归的,但不受实际输入的限制。有关更多示例,请参阅

没有简单的方法来修复你的程序。最简单的方法是使用语法。

答案 1 :(得分:1)

好像你正在滥用Prolog的生成能力,将其追加到最后位置。我试图改变一个更明智的地方:

...
vp([V|R]) :- verb(V), append(NP, PP, R), pp(PP), np(NP).
np([D, N]) :- det(D), noun(N).
np([D|R]) :- det(D), append(AP, [N], R), ap(AP), noun(N).
...

现在你的解析器显然有用了。

?- vp([put, the, red, green, block, on, the, block]).
true .

但我建议,如已经假(+1),切换到DCG进行解析。

答案 2 :(得分:0)

基本问题是Prolog被定义为对规则执行DFS,因此当涉及无限搜索空间中的生成问题时(与您的情况一样),空间的某些部分可以不受影响。与平台无关的修复是使用深度限制来扩充语法,并在每次递归调用时递减深度。一旦深度达到0,则失败。通过重复查询(例如vp(S, 1). vp(S, 2).)逐步增加深度,可以保证状态空间的所有部分最终都会被触及。

这基本上只是迭代加深。如果您使用的是SWI-PL,您还可以使用call_with_depth_limit/3谓词完成相同的操作,而无需修改语法。