为什么这个谓词会留下一个选择点?

时间:2018-07-11 16:25:57

标签: indexing prolog termination

我写了以下谓词:

list_withoutlast([_Last], []). % forget the last element
list_withoutlast([First, Second|List], [First|WithoutLast]) :-
  list_withoutlast([Second|List], WithoutLast).

list_withoutlast(X, [1, 2]).这样的查询确定性地成功,但是即使只有一个答案,list_withoutlast([1, 2, 3], X)这样的查询也会留下选择点。

当我追踪时,似乎SWI试图针对两个子句匹配list_withoutlast([3], Var),即使绝对只有第一个匹配!

还有什么我可以告诉SWI我想要一个包含多个元素的列表吗?或者,如果我想利用第一参数索引的优势,我唯一的选择是“零长度列表”和“非零长度列表”吗?

其他Prolog对这种情况的处理方式是否有所不同?

1 个答案:

答案 0 :(得分:3)

您可以重写谓词以避免虚假选择点:

list_withoutlast([Head| Tail], List) :-
    list_withoutlast(Tail, Head, List).

list_withoutlast([], _, []).
list_withoutlast([Head| Tail], Previous, [Previous| List]) :-
    list_withoutlast(Tail, Head, List).

此定义利用了第一参数索引的优势,该索引将在list_withoutlast /3谓词中区分第一子句和第二子句,第一子句在第一个参数中具有原子(空列表)。 (非空)列表中的第一个参数。

Prolog编程习惯是将输入列表参数的开头和结尾作为单独的参数传递给辅助谓词,以利用第一参数索引并避免虚假的选择点。

请注意,大多数Prolog系统都不应用深度索引。特别是,对于复合术语,索引编制通常只考虑名称和Arity,而没有考虑复合术语参数(一个元素的列表和两个或多个元素的列表共享同一函子)。