删除序言中的重复项

Removing duplicates in prolog

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

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

我创建了一个 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 列表中,

否则它会。

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

提前致谢

让我们先考虑 is_member/2.

来稍微简化一下任务

你写成:

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

考虑将其误读为:

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

练习:我改变了什么?

因此,我推荐如下布局:

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

现在,开始几个测试用例

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

?- is_member(E, Ls).
nontermination

不是一个好兆头!

所以,让我们尝试几个具体案例。例如,a空列表的成员?

?- is_member(a, []).
false.

那是!这是我们所期望的。

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

?- is_member(a, [a]).
false.

这绝对是错误的

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

  1. 写下应该持有的东西
  2. 尝试最一般的查询看看是否可以从程序中获得答案。
  3. 尝试具体测试用例
  4. 思考谓词的实际含义:您可以在多个方向使用谓词,在许多情况下,您描述谓词的方式没有意义。例如,列表和元素都可以已经 给定 ,在这种情况下,"add" 或 "remove".
  5. 没有任何内容

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

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

您现在可以写:

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

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

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

上面的测试用例仍然失败这个片段,这表明程序仍然太具体:

?- is_member(a, [a]).
false.