rth*_*sen 3 prolog text-manipulation non-termination failure-slice
我无法弄清楚这出错的地方.请注意,我对Prolog很新,我确定我错过了一些东西 - 不知道那可能是什么.有人可以帮帮我吗?
谢谢,这是我的代码:
printSentence([]).
printSentence([W|[]]) :-
write(W),
write('.'),
nl.
printSentence([W|R]) :-
write(W),
write(' '),
printSentence(R).
transform([], Result).
transform([Word|Rest], Result) :-
replace(Word, Replacement),
append(Result, Replacement, NewResult),
transform(Rest, NewResult).
replace(my, your).
replace(i, you).
replace(you, me).
replace(am, are).
replace(Word, Word).
test :-
X = [you, are, my, only, hope],
transform(X, Result),
printSentence(Result).
Run Code Online (Sandbox Code Playgroud)
@Junuxx的答案是解决方案的一个步骤; 你的程序还有另一个问题.但第一步:@Junuxx发现了问题并修复了它.尼斯.但是你怎么能发现这样的问题呢?实际上,你问过"无限循环 - 但是怎么样?"
Prolog的优点在于,您通常可以将循环程序本地化为程序的一小部分.这样的片段称为故障片.那就是:没有更多的眼疮阅读冗长的节目!
让我们回到你的计划.如果你加载它,你会收到如下消息:
Warning: /usager/SO/paranoid.pl:13:
Singleton variables: [Result]
这让你已经暗示了一些可能错误的东西.唉,这不是你目前最关心的问题.你最大的问题是目标test循环!
那么你怎么能用很少的努力来实现实际的循环呢?
一种方法是启动跟踪器,它将逐步显示Prolog如何执行此程序.但是,跟踪器会向您显示许多不相关的细节.详细信息,您在Prolog中编程时无需了解.细节,这填补了你的思想,很有可能你会完全错过实际的问题.因此,除非你想花时间在闪烁的线条上,否则远离示踪剂.
另一种方法是在false您的计划中添加目标.记住,你的程序已经循环,所以这样的额外目标不会对你造成太大伤害.为什么要破坏你的程序,这些false目标首先是你从未想过写的?这是因为这些false目标将通过隐藏"不相关"的部分来帮助您检测程序中非终止的罪魁祸首.这是如此,感谢以下观察:
如果 failure-slice(=您的破坏程序)没有终止,那么原始程序也不会终止.
从某种意义上说,失败切片是您的程序不会终止的原因.或者更强烈地说:只要你不改变故障片中的可见部分; 也就是说,只要您通过修改在故障切片中看不到的部件来尝试运气,问题就会持续存在!保证!这不是最好的保证,但它比盲目更好.
这是我作为失败片得到的.我删除了printSentence/1因为片段中不再使用它.我添加了定义append/3.一些Prolog提供append/3了一个你无法修改的内置谓词.在这种情况下使用另一个名称,比如local_append/3- 只是不要忘记替换所有出现!
append([], Zs, Zs) :- false. append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs), false.transform([], Result) :- false.transform([Word|Rest], Result) :- replace(Word, Replacement), append(Result, Replacement, NewResult), false,transform(Rest, NewResult).replace(my, your) :- false.replace(i, you) :- false.replace(you, me).replace(am, are) :- false.replace(Word, Word) :- false.test :- X = [you, are, my, only, hope], transform(X, Result), false,printSentence(Result).
当我加载此故障片时,我得到:
?- test. ERROR: Out of local stack
这是程序不会终止的良好迹象.在我有限的硬件上,它耗尽了所有资源.((为了迂腐,这个程序可能仍然会终止,它可能只需要太多的资源.但请记住:如果故障切片循环,我们有这个,然后整个程序循环.在任何情况下,证明失败的非终止 -切片通常会更容易,因为片段更短)).
一些观察:最初,transform/2曾经是递归的.现在,它不再是.唯一的递归是在内append/3.所以我首先看一下目标,append(Result, Replacement, NewResult)然后尝试弄清楚变量可能是什么.最简单的是第三个参数:NewResult是我们片段中唯一出现的,我们可以用它替换它_.第二个参数的变量Replacement将永远是me.第一个参数(这里我现在要看test/0)将是一个未实例化的变量.所以我们必须考虑目标append(_, me, _).
只需运行append(_, me, _), false即可看到此目标未终止!您也可以通过检查故障片来看到这一点.这是它,再次:
append([], Zs, Zs) :- false. append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs), false.
看看Ys:没有人关心它,它只是"移交".只有第一个和第三个参数可以保证终止!
有关更多信息,请参阅标记failure-slice.
某些限制适用!在禁止的地方无效!您只能使用纯粹的单调Prolog程序进行上述推理.实际上,你的程序中的一些良性副作用也是可以的.只要它们不影响控制流程.
您的程序还有另一个问题.跑去printSentence([you]), false看吧!回溯和副作用不容易聚集在一起.对于初学者来说,最好的方法是尽量避免副作用.看一下这个问题及答案的一个例子,如何消除编程问题中无用的副作用.为什么不叫transform([you, are, my, only hope], Xs)或maplist(replace,[you, are, my only, hope], Xs)直接?它让你再次专注于相关的部分!
| 归档时间: |
|
| 查看次数: |
305 次 |
| 最近记录: |