我写了一个谓词,该谓词过滤了所有6以下的数字的列表,但是prolog找到了多个解决方案。
谓词如下:
sift([], []).
sift([H | T], [H | Res]):- H > 6,
sift(T, Res).
sift([_ | T], Res):-
sift(T, Res).
我问的是:?- sift([1, 7, 2, 13], X).
这将导致:
X = [7, 13]
X = [7]
X = [13]
X = []
我只期望X = [7, 13]
,为什么Prolog会找到所有这些额外答案?
答案 0 :(得分:1)
回溯。
当您键入sift([1,10], X).
时,Prolog可以对sift([H | T], [H | Res])
和sift([_ | T], Res)
进行模式匹配。这意味着Prolog留下一个 choicepoint ,选择一个选项,然后稍后再返回其他谓词。
序言匹配第一个谓词sift([7, 2, 13], [H | Res])
,进一步调用sift([1, 13], Res)
。
但是,它也与第二个谓词sift([_ | [2, 13]], Res)
匹配,并且稍后会回溯到此谓词,跳过7。
如果要过滤掉元素,我们可以通过跳过该元素来解决此问题。
sift([], []).
sift([H | T], [H | Res]) :-
H >= 6,
sift(T, Res).
sift([H | T], Res) :-
H < 6,
sift(T, Res).
这给出了:
?- sift([1, 7, 2, 13], X).
X = [7, 13] ;
false.
一种替代方法是使用Prolog if :
sift2([], []).
sift2([H | T], [H2 | T2]) :-
H >= 6 ->
(H2 = H,
sift2(T, T2)
); sift2(T, [H2 | T2]).
此谓词说“列出清单和可能的答案。如果第一个元素等于或大于6,则列表的第一个元素和答案应匹配,并且过滤后的尾部应与答案的尾部匹配。否则,列表的尾部需要能够产生整个答案。
这避免了回溯,并且将在第一个解决方案之后停止搜索。
?- sift2([1, 7, 2, 13], X).
X = [7, 13].
在打开trace.
的情况下查看两个谓词,以进行进一步的描述。