Prolog:从列表 B 中删除列表 A 中出现的所有元素

Prolog: removing all elements that occur in list A from list B

我正在尝试定义一个谓词 "delete(L1, L2, L3)",它在 L3 等于 L2 减去 L1 中包含的任何这些元素时有效。例如。 delete([1], [1,2,3], X) => 将统一 X = [2,3]。我的代码如下:

isNonElement(_, []).
isNonElement(X, [Y|Z]) :- X \= Y, isNonElement(X,Z).

delete(_, [], []).
delete(Y, [X|W], Z) :- \+(isNonElement(X, Y)), delete(Y, W, Z).
delete(Y, [X|W], [X|Z]) :- isNonElement(X, Y), delete(Y, W, Z).

然而,它似乎不适用于每个测试用例。谁能帮我解决我的代码可能有什么问题?

提前致谢!

此致, Skyfe.

P.S。我无法告诉我的谓词在哪些情况下不能正常工作,因为它是由一个学校系统测试的,它没有告诉我它失败了哪些测试用例。

非常接近

剩下的一个问题是,您正在对不允许这样阅读的谓词应用完全合理的逻辑推理。如果您简单地应用以下极其直接的更改,您的代码将完全按预期工作:

  1. 代替(\=)/2,使用dif/2
  2. 而不是\+(isNonElement(X, Y)),只需写:member(X, Y).

第一个更改总是可取的:它通常会使您的程序在更多方向上可用。第二个更改通过使用纯谓词来避免使用不纯否定。

我们现在总共有:

isNonElement(_, []).
isNonElement(X, [Y|Z]) :- dif(X, Y), isNonElement(X,Z).

delete(_, [], []).
delete(Y, [X|W], Z)     :- member(X, Y), delete(Y, W, Z).
delete(Y, [X|W], [X|Z]) :- isNonElement(X, Y), delete(Y, W, Z).

现在检查一下:首先,您的测试用例:

?- delete([1], [1,2,3], X).
X = [2, 3] ;
false.

按预期工作!

其次,一个变量为L2的案例:

?- delete([], L2, []).
L2 = [] ;
false.

这个好像也很不错

三、另一个变量:

?- delete([X], [1,2,3], Ls3).
X = 1,
Ls3 = [2, 3] ;
X = 2,
Ls3 = [1, 3] ;
X = 3,
Ls3 = [1, 2] ;
Ls3 = [1, 2, 3],
dif(X, 3),
dif(X, 2),
dif(X, 1) ;
false.

现在请注意 X 的不同可能性,以及 dif/2 如何在答案中表示 X 必须 不同于 在这种情况下某些整数。

不纯谓词的使用排除了这种更普遍的用途,并且您的评分系统也可能会尝试这种情况。

请注意,您当然可以轻松地自己实施 member/2。这是最直接的关系之一。但是,还要注意 delete/3 的命名非常糟糕: 命令式 总是暗示特定的使用方向,但我们在这里考虑的关系也承认许多其他使用模式!