删除序言中的重复项
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.
这绝对是错误的!
我建议您从那里开始,然后转向更复杂的定义。以系统的方式处理它:
- 写下应该持有的东西。
- 尝试最一般的查询看看是否可以从程序中获得答案。
- 尝试具体测试用例。
- 思考谓词的实际含义:您可以在多个方向使用谓词,在许多情况下,您描述谓词的方式没有意义。例如,列表和元素都可以已经 给定 ,在这种情况下,"add" 或 "remove".
没有任何内容
要查找程序中意外失败的原因,请使用 program-slicing,例如通过使用以下定义来 概括掉 目标:
:- 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.
我对 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.
这绝对是错误的!
我建议您从那里开始,然后转向更复杂的定义。以系统的方式处理它:
- 写下应该持有的东西。
- 尝试最一般的查询看看是否可以从程序中获得答案。
- 尝试具体测试用例。
- 思考谓词的实际含义:您可以在多个方向使用谓词,在许多情况下,您描述谓词的方式没有意义。例如,列表和元素都可以已经 给定 ,在这种情况下,"add" 或 "remove". 没有任何内容
要查找程序中意外失败的原因,请使用 program-slicing,例如通过使用以下定义来 概括掉 目标:
:- 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.