@Junuxx 的回答是解决问题的一步;您的程序中还有另一个问题。但第一步退后一步:@Junuxx 发现了问题并修复了它。好的。但是你怎么能发现这样的问题呢?实际上,您问的是“无限循环——但如何?”
Prolog 中很酷的地方在于,您通常可以将循环程序本地化为程序的一个非常小的片段。这样的片段称为故障片。那就是:阅读冗长的节目不再令人眼花!
让我们回到你的程序。如果加载它,您将收到如下消息:
警告:/usager/SO/paranoid.pl:13:
单例变量:[结果]
这已经为您提供了一些很可能是错误的提示。唉,这不是你目前最关心的问题。您最大的问题是目标test
循环!
本地化不终止
那么,你如何能够不费吹灰之力地意识到什么是真正的循环呢?
一种方法是启动跟踪器,它将逐步向您展示 Prolog 如何执行该程序。但是,跟踪器会显示很多不相关的细节。细节,在 Prolog 中编程时不需要了解。细节,填满你的脑海,以至于你很可能会完全错过实际的问题。因此,除非您想花时间在充满闪烁线条的屏幕上,否则请远离示踪剂。
另一种方法是将目标添加false
到您的程序中。请记住,您的程序已经循环,因此这些额外的目标不会对您造成太大伤害。false
为什么要用这些你一开始就不想写的目标来破坏你的程序呢?这是因为这些false
目标将通过隐藏“不相关”部分来帮助您检测程序中未终止的罪魁祸首。之所以如此,要归功于以下观察:
如果失败切片(=您被破坏的程序)没有终止,那么原始程序也不会终止。
从某种意义上说,故障片是程序不终止的一个原因。或者更强烈地说:只要您不更改 failure-slice 中的可见部分;也就是说,只要你只是通过修改故障切片中不可见的部分来碰碰运气,问题就会持续存在!保证!这不是最好的保证,但总比盲目好。
这是我得到的失败片段。我删除printSentence/1
了,因为它不再在片段中使用。我添加了append/3
. 一些 Prologs 提供append/3
了一个你不能修改的内置谓词。在这种情况下,请使用其他名称,例如local_append/3
- 只是不要忘记替换所有出现的地方!
附加([],Zs,Zs):-假。
附加([X|Xs],Ys,[X|Zs]):-
追加(Xs,Ys,Zs),假。
变换([],结果):-假。
变换([字|休息],结果): -
替换(字,替换),
追加(结果,替换,新结果),假,
变换(休息,新结果)。
替换(我的,你的):-假的。
替换(我,你):-假。
替换(你,我)。
替换(我,是):-假。
替换(字,字): -假。
测试 :-
X = [你,是,我的,唯一的,希望],
变换(X,结果),假,
printSentence(结果)。
当我加载这个故障片时,我得到:
?- 测试。
错误:超出本地堆栈
这很好地表明程序不会终止。在我有限的硬件上,它反而耗尽了所有资源。((学究起来,这个程序可能仍然会终止,它可能只需要太多资源。但请记住:如果失败切片循环,则我们有这个,然后整个程序循环。无论如何,证明失败的非终止-切片通常会更容易,因为片段更短))。
一些观察:最初,transform/2
曾经是递归的。现在,它不再是了。剩下的唯一递归是在append/3
. 因此,我首先查看目标append(Result, Replacement, NewResult)
,然后尝试找出变量可能是什么。最简单的是第三个参数:NewResult
是我们片段中唯一出现的,因此我们可以将其替换为_
. 第二个参数的变量Replacement
总是me
. 第一个参数(这里我现在要看看test/0
)将是一个未实例化的变量。所以我们要考虑目标append(_, me, _)
。
简单运行append(_, me, _), false
看看这个目标不会终止!您也可以通过检查故障切片来看到这一点。再说一遍:
附加([],Zs,Zs):-假。
附加([X|Xs],Ys,[X|Zs]):-
追加(Xs,Ys,Zs),假。
看Ys
:没人管,就是“交”了。只有第一个和第三个参数可以保证终止!
有关更多信息,请参阅标签failure-slice。
印刷精美
某些限制适用!禁止的地方无效!您只能使用纯粹的单调 Prolog 程序进行上述推理。实际上,程序中的一些良性副作用也是可以的。只要它们不影响控制流。
另一个问题
您的程序还有另一个问题。跑printSentence([you]), false
过去看看!回溯和副作用不会轻易聚集在一起。对于初学者来说,最好的办法是一起避免副作用。有关如何消除编程问题中无用的副作用的示例,请参见这个问题和那个答案。为什么不打电话transform([you, are, my, only hope], Xs)
或maplist(replace,[you, are, my only, hope], Xs)
直接打电话?它让您再次专注于相关部分!