Prolog如何使用回溯找到解决方案?

时间:2019-05-09 21:54:26

标签: prolog subset backtracking

我有这个生成子集的序言代码。

subset([], []).

subset([E|Tail], [E|NTail]):-
     subset(Tail, NTail).

subset([_|Tail], NTail):-
     subset(Tail, NTail).

该代码有效,但我不知道该怎么做。我试图使用跟踪来逐步找到它的解决方案,但我根本不理解。

如果有人可以逐步引导我了解prolog如何找到它,例如

这样的简单查询的解决方案
subset([1,2,3],X).

那将是最有帮助的。

1 个答案:

答案 0 :(得分:2)

Prolog试图证明subset([1,2,3],X).是事实。通过尝试查看是否有任何谓词支持该目标来实现此目的。

最初,它尝试subset([], []).-失败,因为[1,2,3]无法与[]统一。

然后尝试subset([E|Tail], [E|NTail]):- subset(Tail, NTail).。它可以与头部统一,因此现在尝试证明尾巴。它试图证明subset([2,3], NTail)

这导致证明subset([3], NTail)(不同的NTail),然后证明subset([], NTail)(再次证明NTail)。现在,它以subset([], []).成功-终止深度优先搜索,然后继续进行调用堆栈的构建,建立X的结果-[1|[2|[3|[]]]][1, 2, 3]

结果是,目标?- subset([1,2,3],X).成功了[1, 2, 3]

现在,如果您要求Prolog提供第二个答案,则它将查看成功的最后一个谓词,并假定失败。这就是目标subset([], NTail)。没有可以成功实现该目标的谓词,因此它又退了一步。用subset([3], NTail)证明了subset([E|Tail], [E|NTail]):- subset(Tail, NTail).,但现在它会假设失败了,因此继续进行并尝试subset([_|Tail], NTail):- subset(Tail, NTail).成功,并有效地丢弃了3,因此像以前一样继续继续证明目标。最终得到[1, 2]

如果您要求Prolog给出另一个答案,它将继续使用这种方法,返回并找到成功的最后一件事情,并假设它失败并继续。

最终您会得到以下结果:

[1, 2, 3]
[1, 2]
[1, 3]
[1]
[2, 3]
[2]
[3]
[]