【问题标题】:English constraint free grammar prolog英语无约束语法序言
【发布时间】:2013-03-27 20:02:05
【问题描述】:

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

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

    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] 因为它首先将左侧“red”的形容词短语扩展为前所未有的无限可能在右边尝试。

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

【问题讨论】:

  • 我认为你的意思是上下文无关语法。

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


【解决方案1】:

简短的回答是:使用定句语法 () 来表示您的语法。典型编码见this answer

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

动词(S):- 成员(S,[put,pickup,stack,unstack])。 det(S) :- 成员(S, [the])。 adj(S) :- member(S, [big, small, green, red, yellow, blue])。 名词(S) :- false, member(S, [block, table])。 准备(S):-成员(S,[on,from])。 vp([V|R]) :- 动词(V), pp(PP), false, np(NP), append(NP, PP, R)np([D, N]) :- false,det(D),名词(N)。 np([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])。

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

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

【讨论】:

  • @DanielLyons:这就是失败切片的想法:你必须改变可见部分的一些东西。删除线部分无关紧要。
  • @DanieLyons:您将终止与意外找到答案混淆了。是的,有时你会得到答案。但是你不能轻易预测什么时候。还可以将vp(_). 作为事实添加到顶部...
  • @DanielLyons:整个故障片是程序没有终止的原因。请记住,Prolog 和 DCG 都是为了准确解决这个问题而开发的。
  • 回去后我发现我误读了 OP 的问题。我为火焰战争道歉。
  • @DanielLyons:没关系!您是否删除了自己的 cmets? (我没有标记它们;发现它们没问题)。但无论如何:我认为你可以从背后的失败切片的概念中获益良多。
【解决方案2】:

似乎您在滥用 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 .

但我建议,正如已经错误的 (+1) 一样,切换到 DCG 进行解析。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这个问题是关于语法的,其中输入列表可用于显着限制搜索空间 - 通常降至最小线性情况。迭代深化通常很好,但天真地应用会导致令人望而却步的开销。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多