【问题标题】:prolog dcg restrictionprolog dcg 限制
【发布时间】:2013-01-10 01:25:09
【问题描述】:

我想使用 DCG 作为发电机。截至目前,语法是

s-->a,b.
a-->[].
a-->a,c.
c-->[t1].
c-->[t2].
b-->[t3].
b-->[t4].

我想生成所有s,其中a 的长度为< someNumber

使用?- phrase(a,X),length(X,Y),Y<4. 我可以得到所有a 少于4 个项目。但是,当所有组合都用尽时,系统 (SWI-Prolog 6.2.5) 似乎停止运行。 有时,类似的问题是asked here。但是,作为 Prolog 的新手,我无法使其与上述语法一起使用。有什么想法吗?

更新:(canrememberthename) 的一条评论不知何故被删除了。无论如何,建议使用between(1,4,Y),length(X,Y),phrase(a,X). 设置限制。在将我的代码更改为 a-->c,a.

之后,这很好用

【问题讨论】:

  • 我删除了答案,因为是错误的。我调试的时候你自己发现了问题...

标签: prolog dcg failure-slice


【解决方案1】:

进入 Prolog 的第一步通常有点困难。但你走在正确的轨道上:

目前,您的问题是您得到了一些预期的答案/解决方案,但随后系统停止了;实际上,它处于无限循环中。您通过耐心地点击 SPACE 发现了这一点。这可能适用于一小部分解决方案,但使用更大的解决方案会很乏味。想想看所有短于 20 的句子。

有一种简单的键盘和腕管友好方式来模拟击球空间:只需在末尾添加一个目标 false,如下所示:

?- 短语(a,X),长度(X,Y),Yfalse。

Prolog 能回答这样一个问题吗?由于末尾有false,Prolog没有太多选择:要么自己回答false;或者它循环(或产生错误或产生一些副作用)。在这种情况下,它会循环。

现在,我们可以通过在您的计划中添加更多 false 目标来缩小问题范围。

?- 短语(a,X),长度(X,Y),false,Yfalse。 **循环**

为了更好地阅读,我将只使用一个 false 目标并删除查询的其余部分:

?- 短语(a,X),长度(X,Y),falseY。 **循环**

让我们进一步减少它:

?- 短语(a,X),false,length(X,Y),Y。 **循环**

他们都在循环!但是我们得到了一些有趣的见解:由于这些 false 修饰的查询不会终止,因此原始程序也不会终止。因此,当您查看查询时,如果第一个目标本身并未终止,则整个查询也不会终止(有关更多信息,请参阅末尾的细则)。

因此:您必须以某种方式解决第一个目标!

我的第一次尝试是交换lengthphrase

?- 长度(X,Y),短语(a,X),Y

这行得通吗?看看第一个循环的目标:

?- 长度(X,Y), false, phrase(a,X), Y。

所以这又不会终止。

您必须再次更改程序:

?- between(1,3,Y), length(X,Y), false, phrase(a,X)。 错误的。

这样就结束了。如果出现终止问题,phrase(a,X) 现在必须承担责任:

?- between(1,3,Y),长度(X,Y),短语(a,X),false。 **循环**

您可能很想查看实际答案:

?- 在(1,3,Y)之间,长度(X,Y),短语(a,X)。 Y = 1, X = [t1] ; Y = 1, X = [t2] ; 错误:超出本地堆栈

您可能会得出结论,这种行为比您最初的定义更糟糕。毕竟,我们现在的答案比以前。但正是这种推理并不能帮助您改善终止: false 两者 都是同一种错误,您必须首先解决这个问题。因此,通过隐藏答案,您可以更好地专注于其余部分。

但是为什么你的语法有问题?我们可以继续使用我们的技术插入目标 false 以缩小范围。但这次在你的语法范围内。您的带有目标false的程序称为

只是一个实用的说明:当我在你的程序中插入目标 false 时,我将保存程序并在 SWI 中输入make:这样程序会快速重新编译。

经过一番尝试,我得到了以下最小故障片。请注意,在 DCG 中,false 必须写为 {false}

?- between(1,3,Y), 长度(X,Y), 短语(a,X), false s--> {false}, a,ba-->[], {假}。 a-->a,{false},cc-->{false},[t1]c-->{false},[t2]b-->{false},[t3]b-->{false},[t4]

几乎你所有的代码库都属于false!所以你必须解决微小的可见剩余部分。在其他地方改变一些东西是没有意义的。这个a --> a, ... 必须改!事实上,将其更改为 a --> c, s 即可解决问题。

你当初为什么写a --> a, c.?我怀疑您想以公平的方式列举所有解决方案。新版本没有:

?- 短语(a,X)。 X = [] ; X = [t1] ; X = [t1, t1] ; X = [t1, t1, t1] ; X = [t1, t1, t1, t1] ; X = [t1, t1, t1, t1, t1] ; X = [t1, t1, t1, t1, t1, t1] ; X = [t1, t1, t1, t1, t1, t1, t1] ...

这看起来很吓人。事实上,它看起来是错误的。不是吗?但是不要让您对此感到困惑:我们这里有无限的句子集。所以 Prolog 唯一正确的反应是产生无限多的答案。因为,如果它们是有限的,就会丢失一些列表!但是,当然,您希望看到以公平的方式列举它们。要得到这个,只需写:

?- 长度(X,N),短语(a,X)。 X = [], N = 0 ; X = [t1], N = 1 ; X = [t2], N = 1 ; X = [t1, t1], N = 2; X = [t1, t2], N = 2; X = [t2, t1], N = 2; X = [t2, t2], N = 2; X = [t1, t1, t1], N = 3 ...

这是 Prolog 程序中的一个要点:始终首先寻求最佳(可能)终止属性。并且不要看 Prolog 如何枚举答案的精确顺序。因为,如果一个程序具有更好的终止属性,那么使用它以公平的方式枚举所有解决方案几乎是微不足道的。但是:以公平的方式以终止为代价枚举无限多个解决方案的程序不能用于更有趣的情况。

细则
See this answer.

【讨论】:

  • “你所有的代码库都属于假”也许是我在 StackOverflow 上的 Prolog 答案中读到的最好的陈述。谢谢你的微笑
【解决方案2】:

非终结符 a//0 既是左递归又是 'epsilon'(生成空序列),phrase/2 将在空产生式之后立即循环。

你可以解决你的问题边界列表的长度:

?- between(1,4,Y),length(X,Y),phrase(a,X).

并且,正如您已经完成的那样,删除左递归。

【讨论】:

    猜你喜欢
    • 2011-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多