我试图找出这个问题,但没有成功 你能告诉我什么是错?序言deleteall不起作用
% 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).
我试图找出这个问题,但没有成功 你能告诉我什么是错?序言deleteall不起作用
% 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).
辛格尔顿变量总是疑神疑鬼,对你来说,什么是V的含义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.
从你的代码,它似乎想要基于统一deleteall语义(另一种是删除只使用(==)/ 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)
).
对于纯粹的解决方案,请考虑this answer – note the different argument order。
但实际的问题是:什么是错你解决方案?
有一种方法,其方式是独一无二的Prolog的回答这个。在其他编程语言中,你必须找出有意义的测试用例。然后,您将使用这些测试用例来查看您的实现是否有效。当然,在Prolog中也是如此。
不过想想实际成本弄清楚这些测试用例!你必须全面了解整个关系。你将不得不精心打印精神上存在的数据结构。这是相当智力的努力。你的例子非常简单,所以这个努力似乎很小。但想象一下在这里和那里添加的更多细节。
那么怎样才能找出一个测试用例谓语不理解实际的关系?
只需采取最一般的查询。也就是说,在所有参数中都有一个具有不同变量的目标对于你的例子,那将是deleteall(X, Xs, Ys)
。现在,我们的工作已经完成,我们可以让Prolog填补空白。
?- deleteall(X,Xs,Ys). Xs = Ys, Ys = [] ; Xs = [X] ; false.
根据您的定义,我们得到两个答案。第一个答案包含Xs
为空列表[]
的解决方案。第二个答案包含Xs
是一个元素列表的解决方案。这就是你所有的关系描述。
包含两个或更多元素的列表如何?他们没有解决方案。所以,你的定义在这方面太具体了。
第二个答案适用于所有Ys
。例如。根据你的定义,deleteall(1,[1],[2,3])
也保留–。更糟糕的是:deleteall(1,[1],[1]).
根本没有删除。所以你的定义太笼统了。
这是怎么回事?那么,你必须编写纯粹的单调程序。也就是说,不得使用不完整的内置插件,如!/0
,(\+)/1
,(\=)/2
,(\==)/2
,并且不得使用(或非常特别小心地使用)内置插件。