进入 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),
false,
Y。
**循环**
让我们进一步减少它:
?- 短语(a,X),
false,
length(X,Y),Y。
**循环**
他们都在循环!但是我们得到了一些有趣的见解:由于这些 false 修饰的查询不会终止,因此原始程序也不会终止。因此,当您查看查询时,如果第一个目标本身并未终止,则整个查询也不会终止(有关更多信息,请参阅末尾的细则)。
因此:您必须以某种方式解决第一个目标!
我的第一次尝试是交换length和phrase:
?- 长度(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的程序称为failure-slice。
只是一个实用的说明:当我在你的程序中插入目标 false 时,我将保存程序并在 SWI 中输入make:这样程序会快速重新编译。
经过一番尝试,我得到了以下最小故障片。请注意,在 DCG 中,false 必须写为 {false}。
?- between(1,3,Y), 长度(X,Y), 短语(a,X),
false
s--> {false}, a,b。
a-->[], {假}。
a-->a,
{false},
c。
c-->{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.