【问题标题】:Why does this predicate leave behind a choicepoint?为什么这个谓词会留下一个选择点?
【发布时间】:2018-07-11 16:25:56
【问题描述】:

我写了以下谓词:

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 对这种情况的处理方式有什么不同吗?

【问题讨论】:

  • @Paulo 为什么要删除 SWI-Prolog 标签?
  • 这个问题很笼统。因此,通过使用通用的Prolog 标签,我们告诉其他人相同的问题和解决方案适用于其他 Prolog 实现。

标签: indexing prolog termination


【解决方案1】:

你可以重写你的谓词来避免虚假的选择点:

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谓词中区分第一个子句,第一个子句在第一个参数中有一个原子(空列表),第二个子句有一个(非-empty) 在第一个参数中列出。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 2011-01-24
    相关资源
    最近更新 更多