prolog deleteall不起作用

时间:2012-05-28 13:53:19

标签: prolog accumulator

我试图找出问题但没有成功 你能告诉我出了什么问题吗?

% 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).

3 个答案:

答案 0 :(得分:1)

对于纯解决方案,请考虑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和副作用内置插件(或非常特别小心使用)。

答案 1 :(得分:0)

单身变量总是可疑的,在你的情况下,deleteall(X, [X|Xs], Xs, V).中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 :(得分:0)

从您的代码中,您似乎想要基于统一的删除所有语义(另一种方法是仅使用(==)/ 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)
    ).