1

我对 prolog 还很陌生,目前正在阅读一本书,该书为我提供了代码练习示例。它要求我删除重复项。

注意:我已阅读其他 stackoverflows,并且我了解如何删除重复项,但我不明白为什么我的代码无法正常工作。(我为其他 stackoverflows 选择了不同的方法)

我创建了一个 is_member 谓词,我认为它可以正常工作。

is_member(X, [Head,Tail]):-
    X == Head;
    is_member(X, Tail).

然后我的 remove_duplicates 谓词

remove_duplicates([Head|Tail], Without):-
    is_member(Head, Tail),
    remove_duplicates(Tail, Without);
    remove_duplicates(Tail, Head).

在我看来这是有道理的,它检查 Head 是否是 tail 的成员,如果是,它不会将其添加到 Without 列表中,

否则它会。

我显然在这里遗漏了一些微不足道的东西,

提前致谢

4

1 回答 1

3

让我们先考虑一下,稍微简化一下任务is_member/2

你把它写成:

is_member(X, [头,尾]):-
    X == 头部;
    is_member(X,尾巴)。

考虑一下很容易将其误读为:

is_member(X, [头,尾]):-
    X == 头,
    is_member(X,尾巴)。

练习:我改变了什么?

出于这个原因,我推荐如下布局:

is_member(X, [头,尾]):-
        ( X == 头
        ; is_member(X, 尾)
        )。

现在,开始几个测试用例

首先,发布最一般的查询总是一个好主意。这只是问:是否有任何解决方案?

?- is_member(E, Ls)。
不终止

可不是什么好兆头!

那么,让我们尝试一些具体的案例。例如,a空列表的成员吗?

?- is_member(a, [])。
的。

很好!这是我们所期望的。

那么,是a列表的成员[a]吗?

?- is_member(a, [a])。
的。

那肯定是的!

我建议您从那里开始,然后继续进行更复杂的定义。以系统的方式处理它:

  1. 写下应该持有的东西。
  2. 尝试最一般的查询,看看您是否可以从您的程序中获得答案。
  3. 尝试具体的测试用例
  4. 想想谓词的实际含义:您可以在多个方向使用谓词,在许多情况下,您描述谓词的方式没有意义。例如,列表和元素都可以已经给出,在这种情况下,没有什么可以“添加”或“删除”。

要定位程序中意外失败的原因,请使用,例如通过使用以下定义来概括目标:

:- op(950,fy, *)。
*_。

你现在可以写:

is_member(X, [头,尾]):-
        (    *  X == Head 
        ;    *  is_member(X, Tail)
        )。

这是对您的原始程序的大规模概括,实际上在声明上等同于:

is_member(X, [Head,Tail]) :- true

上面的测试用例仍然因为这个片段而失败,这表明程序仍然过于具体

?- is_member(a, [a])。
的。
于 2016-11-16T19:33:15.997 回答