您可以使用递归构建谓词remove_list/3,这在处理Prolog 中的列表时是一个有用的工具。
remove_list([], _, []).
remove_list([X|Tail], L2, Result):- member(X, L2), !, remove_list(Tail, L2, Result).
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).
Consult:
?- remove_list([4,5,1,6,3], [1,4,7], L).
L = [5, 6, 3].
这个想法是将原始列表“L1”中的每个元素复制到最终列表“L”中,除非该元素是第二个列表“L2”的成员。
您的基本子句是您的停止条件,当您的原始列表“L1”为空时,在这种情况下忽略您的列表“L2”,结果始终是相同的空列表。 (您无法从空列表中删除任何内容)。
您的第二个子句,如果头部中的元素是列表“L2”的成员,则不要将列表“L1”头部中的元素复制到最终列表“L”,同时对谓词进行递归调用列表的尾部“L”。
最后一个子句,将列表“L1”头部的元素复制到最终列表“L”,并递归调用该列表“L”尾部的谓词。这里我们不需要目标member/2,因为我们在上一个子句中使用了剪切。
EDIT:仅当您想要从“L2”列表中包含的列表“L1”中删除项目(无论顺序如何)时,才应考虑此答案。要从集合“L1”中删除子集“L2”,请使用潜伏者的解决方案 https://stackoverflow.com/a/29240568/553029或其他解决方案:
remove_list(L, [], L):- !.
remove_list([X|Tail], [X|Rest], Result):- !, remove_list(Tail, Rest, Result).
remove_list([X|Tail], L2, [X|Result]):- remove_list(Tail, L2, Result).
这个新的解决方案考虑了列表“L2”中元素的顺序,但不是严格意义上的,即可能散布在原始列表“L1”中,这并不违反“L2”是“L2”的子集的概念。 L1”。
[2,4] 是集合 [1,2,3,4,5,6] 的子集,但 [2,4,7] 不是:
?- remove_list([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].
?- remove_list([1,2,3,4,5,6], [4,2], L).
false.
?- remove_list([1,2,3,4,5,6], [2,4,7], L).
false.
现在,考虑到我们希望获得原始集合而不是在可以删除原始集合中的任何元素的情况下获得否定响应,那么我们使用辅助谓词:
rm_subset(L1, L2, L):- remove_list(L1, L2, L),!.
rm_subset(L1, L2, L1).
Consult:
?- rm_subset([1,2,3,4,5,6], [4,2], L).
L = [1, 2, 3, 4, 5, 6].
?- rm_subset([1,2,3,4,5,6], [2,4], L).
L = [1, 3, 5, 6].