英语无约束语法prolog

英语无约束语法prolog,prolog,infinite-loop,dcg,left-recursion,failure-slice,Prolog,Infinite Loop,Dcg,Left Recursion,Failure Slice,在prolog中实现一个非常简单的无约束语法时,我遇到了一个无限递归问题 以下是我的规则:(vp->动词短语,np->名词短语,ap->形容词短语,pp->预备短语) 我遇到的问题是,ap的规则可以产生任意长的形容词字符串,所以在某个时候,我试图通过尝试所有这些无限的可能性来满足查询 例如,下面的查询永远不会生成S=[put,the,red,block,on,the,green,block],因为它会首先将左侧的形容词短语“red”扩展到无限可能,然后再尝试右侧 ?- vp(S) S = [pu

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

以下是我的规则:(vp->动词短语,np->名词短语,ap->形容词短语,pp->预备短语)

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

例如,下面的查询永远不会生成S=[put,the,red,block,on,the,green,block],因为它会首先将左侧的形容词短语“red”扩展到无限可能,然后再尝试右侧

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

简单的回答是:使用Definite子句语法()来表示您的语法。有关典型的编码,请参阅

但现在来谈谈你程序中的实际问题。你不仅得不到想要的答案;情况更糟:即使在一个简单得多的程序片段中,您也会遇到同样的问题。以下是您的程序中尚未终止的最小片段:

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]). 动词:—成员[put,pickup,stack,unstack])。 代表:成员,[代表]。 形容词:成员[大、小、绿、红、黄、蓝]。 名词:-false,成员[块,表])。 准备工作:—成员[开始,开始]。 动词短语([V | R]):-动词(V),pp(pp),false,np(np),append(np,pp,R)。 名词短语([D,N]):-false,det(D),名词(N)。 名词短语([D | R]):-det(D),ap(ap),false,名词(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])。 通过插入goals
false
我们得到了您的程序的一小部分仍然没有终止。 实际源是
ap/1
,它是递归的,但不受实际输入的限制。有关更多示例,请参见


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

似乎你在滥用Prolog的生成能力,将append放在最后一个位置。我试着换一个更明智的地方:

...
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 .

但是,正如false所做的(+1),我建议切换到DCG进行解析。

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


这基本上只是迭代深化。如果您使用的是SWI-PL,您也可以使用谓词执行完全相同的操作,而无需修改语法。

我认为您指的是上下文无关语法。@DanielLyons:这正是失败切片的概念:您必须更改可见部分中的某些内容。“划破部分是无关紧要的。@DanieLyons:你把终止和意外找到答案混为一谈。是的,有时候你会得到答案。但你不能轻易预测什么时候。另外,添加
vp(389;)。
作为上面的一个事实也可以…@DanielLyons:整个失败部分是程序没有终止的原因。请记住,Prolog和DCGs都是为了解决这个问题而开发的。回到过去,我发现我误读了OP的问题。“我为这场火焰战道歉。”丹尼:没关系!你删除自己的评论了吗?(我没有标记它们;发现它们正常)。但是在任何情况下:我认为你可以从后面的失败切片的概念中获益匪浅。这个问题是关于语法的,在语法中,输入列表可以用来极大地限制搜索空间——通常是最小线性情况。迭代深化通常是好的,但天真地应用会导致令人望而生畏的开销。
?- vp([put, the, red, green, block, on, the, block]).
true .