我试图找出问题,但没有成功 你能告诉我哪里出了问题吗?
% using accumulator
deleteall(X,Y,Zs) :- deleteall(X,Y, [], Zs).
deleteall(X, [], Zs, Zs).
deleteall(X, [X|Xs], Xs, V).
deleteall(X, [Y|Xs], [Y|Zs], V) :- deleteall(X, Xs, Zs,V).
我试图找出问题,但没有成功 你能告诉我哪里出了问题吗?
% using accumulator
deleteall(X,Y,Zs) :- deleteall(X,Y, [], Zs).
deleteall(X, [], Zs, Zs).
deleteall(X, [X|Xs], Xs, V).
deleteall(X, [Y|Xs], [Y|Zs], V) :- deleteall(X, Xs, Zs,V).
对于纯粹的解决方案,请考虑这个答案——注意不同的参数 order。
但是您的实际问题是:您的解决方案有什么问题?
有一种方法可以以 Prolog 独有的方式来回答这个问题。在其他编程语言中,您必须找出有意义的测试用例。然后,您将使用此类测试用例来查看您的实现是否有效。当然,这在 Prolog 中也是可能的。
但是想想找出这些测试用例的实际成本!您必须详细了解整个关系。您必须在脑海中掌握有关数据结构的所有细则。这是一项相当智力的努力。您的示例非常简单,因此这种努力似乎是微不足道的。但是想象一下这里和那里添加了一些进一步的细节。
那么我们如何在不了解实际关系的情况下找出谓词的测试用例呢?
只需采取最一般的查询。也就是说,在所有参数中都有不同变量的目标。对于您的示例,那将是deleteall(X, Xs, Ys)
. 现在,我们的工作已经完成,我们可以让 Prolog 来填补空白。
?-删除所有(X,Xs,Ys)。 Xs = Ys, Ys = [] ; Xs = [X] ; 错误的。
根据您的定义,我们得到两个答案。第一个答案包含Xs
作为空列表的解决方案[]
。第二个答案包含Xs
作为一个元素列表的解决方案。这就是你的关系所描述的全部。
包含两个甚至更多元素的列表呢?他们没有解决方案。因此,您的定义在这方面过于具体。
第二个答案适用于所有人Ys
。例如deleteall(1,[1],[2,3])
,根据您的定义,也成立。更糟糕的是:deleteall(1,[1],[1]).
根本没有删除。所以你的定义在这里太笼统了。
这一切的关键在哪里?好吧,你必须编写纯粹的、单调的程序。也就是说,不得使用不纯的内置插件,如、 、和具有副作用的内置插件(或非常小心地使用!/0
)(\+)/1
。(\=)/2
(\==)/2
单例变量总是可疑的,在您的情况下, V in 的含义是deleteall(X, [X|Xs], Xs, V).
什么?
除此之外,我不明白你为什么使用蓄电池。
您是否指定反转未删除的元素?否则,这是一个有效的 deleteall...
deleteall(_, [], []).
deleteall(X, [X|Xs], Zs) :- !, deleteall(X, Xs, Zs).
deleteall(X, [Z|Xs], [Z|Zs]) :- deleteall(X, Xs, Zs).
测试:
?- deleteall(2,[1,2,3,54,2,1,4,2],X).
X = [1, 3, 54, 1, 4] ;
false.
从您的代码来看,您似乎想要基于统一的删除所有语义(另一种方法是仅删除使用 (==)/2 相等的术语)。所有列表元素(以及您要删除的元素)是否总是接地?如果没有,只要您要删除的元素被部分实例化,并且在与列表元素之一统一时进一步实例化,您的代码就会失败。您可以通过在正文中使用双重否定来解决这个问题,而不是头部统一。正如“chac”已经指出的那样,您还留下了选择点。使用 cut 或 if-then-else 可以解决该问题。改进代码的另一种方法是将列表移动到第一个参数,允许 Prolog 的第一个参数索引为您提供更好的性能(当然,假设,对谓词的调用将实例化第一个参数)。遵循以下定义:
delete_all([], _, []).
delete_all([X|Xs], Y, Zs) :-
( \+ X \= Y ->
delete_all(Xs, Y, Zs)
; Zs = [X|Zs0],
delete_all(Xs, Y, Zs0)
).