删除序言

时间:2016-11-16 19:20:37

标签: list prolog failure-slice

我对prolog很新,而且我正在阅读一本书,它正在给我练习代码的例子。它的任务是删除重复项。

注意:我已经读过其他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是否是尾部的成员,如果是,它不会将它添加到Without列表中,

否则确实如此。

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

提前致谢

1 个答案:

答案 0 :(得分:3)

让我们先考虑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)
        ).

现在,进行一些测试用例

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

?- is_member(E, Ls).
nontermination

那是不是一个好兆头!

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

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

那是!这是我们的期望。

然后,a[a]列表的成员吗?

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

这绝对是错误

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

  1. 写下应该举行的
  2. 尝试最常见的查询,看看您是否可以从您的计划中获得答案。
  3. 尝试具体测试用例
  4. 考虑谓词实际上意味着什么:您可以在多个方向上使用谓词,在许多情况下,您描述谓词的方式没有意义。例如,列表和元素都已经给定,在这种情况下,没有“添加”或“删除”。
  5. 要查找程序中意外失败的原因,请使用,例如使用以下定义概括目标:

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

    您现在可以写:

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

    这是您原始程序的大规模泛化,实际上声明性地等同于:

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

    上面的测试用例仍然无法这个片段,表明该程序仍然太具体

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