我的老师为我们提供了一些关于Prolog的幻灯片,我发现了一些有点奇怪的东西。
reverse([],[]).
reverse([X|Xs],Zs) :- reverse(Xs,Ys), append(Ys, [X], Zs).
据他说,当第一个参数reverse([],..)
是完整列表时,程序终止。
此外,如果您将谓词中的目标切换为reverse([X|Xs],Zs) :- append(Ys, [X], Zs), reverse(Xs,Ys).
,则当第二个参数是完整列表reverse(..,[]).
时,程序应该终止
这与我迄今为止学到的东西有点不同。我认为这两个论点都影响了节目的终止条件,显然它们并不符合我老师的例子。 任何人都可以给我一些意见吗?
答案 0 :(得分:4)
由于Prolog相对复杂的控制流程,Prolog程序的终止属性有点难以理解。有很多方法可以降低复杂性。一个是通过在程序中插入其他目标 false
来仅考虑部分计划。你可以把它们放在任何地方。无论你把它们放在哪里,下面都有:如果这个名为failure-slice的新程序没有终止,那么你的原始程序也不会终止。注意“如果”。这是你的计划:
reverse([],[]) :- false. reverse([X|Xs],Zs) :- reverse(Xs,Ys), false,append(Ys, [X], Zs).
此故障切片对于理解您的关系所描述的完全没用。它永远不会成功。但是,它有助于我们更好地理解 终止将如何做。
请注意,事实已完全消除。事实上,无论事实如何,它都无法改善reverse/2
这个失败切片的终止。 (但它可能会使终止恶化)。
另请注意第二个参数Zs
:没有进一步提及此Zs
。因此:reverse/2
的第二个参数可以是它想要的任何东西。它将再次无法改善终止。
要使reverse/2
终止,必须实例化第一个参数,以便此片段终止。因此,[]
,[X|[]]
将终止,即使[X|nonlist]
也会终止。但部分列表(例如Xs
,[a|Xs]
等不会终止。
如果你想改善终止,比如reverse(Xs,[])
你需要改变可见的剩余部分。一种方法是交换目标。现在,Zs
可能会导致终止。但是-alas-第一个论点现在不再具有它曾经拥有的影响力。考虑reverse([a], Zs)
和:
reverse([],[]) :- false. reverse([X|Xs],Zs) :- append(Ys, [X], Zs), false,reverse(Xs,Ys).append([], Zs, Zs) :- false. append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs), false.
因此,虽然这个片段仍然坚持第一个参数是[_|_]
,但它并没有考虑剩余的术语。因此,目标不会终止。
如果您想了解更多信息,请查看failure-slice。同样,请考虑using cTI。为了培养良好的直觉,你需要自己尝试一下。