我对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列表中,
否则确实如此。
我显然在这里遗漏了一些微不足道的事情,
提前致谢
答案 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.
这绝对是错误!
我建议你从那里开始,然后继续进行更复杂的定义。以系统的方式处理它:
要查找程序中意外失败的原因,请使用program-slicing,例如使用以下定义概括目标:
:- 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.