为什么Prolog在过滤列表时会找到许多解决方案?

时间:2019-11-10 00:01:09

标签: prolog

我写了一个谓词,该谓词过滤了所有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会找到所有这些额外答案?

1 个答案:

答案 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.的情况下查看两个谓词,以进行进一步的描述。