4

我想从列表中删除所有包含[['One', _], _]. 我创建了以下子句,delete_all它始终有效,但我的情况除外:

delete_all(_,[],[]) :- !.
delete_all(X,[X|Tail],List) :-
    !,
    delete_all(X,Tail,List).
delete_all(X,[A|Tail],[A|List]) :-
    delete_all(X,Tail,List).

示例:(这很好用)

?- delete_all(3,[3,4,3,5,3],K).
K = [4, 5] .

但这效果不佳:

delete_all([['One', _], _], [[['One', 'Six'], 94],
    [['One', 'Ten'], 13], [['Two', 'Nine'], 35]], Y).
Y = [[['One', 'Ten'], 13], [['Two', 'Nine'], 35]].

为什么它只删除第一个元素?有什么问题?

4

2 回答 2

1

我想问题在于您的第一个术语(您正在搜索的模式)包含变量,并且在您扫描列表时这些变量与列表元素“统一”。一旦您传递了一个匹配的元素,模式中的变量就会被实例化为该元素中相应术语的值,从而防止进一步匹配。

一个可能的解决方案是检查您的模式和元素是否可以统一,但最终不能统一。

像这样的东西可能适合您的需求:

delete_all(_,[],[]):-!.

delete_all(X,[H|Tail],List):-
    unifiable(X, H, _),
    !,
    delete_all(X,Tail,List).

delete_all(X,[A|Tail],[A|List]):-
    delete_all(X,Tail,List).

如果您使用的是 Yap,则必须导入library(terms)

:- use_module(library(terms)).

另一种解决方案可能是使用棘手的not(not(X = H))而不是unifiable,它确实检查您是否可以统一 H 和 X,如果您可以内部不阻止实例化并且第二个返回 true。

更新:正如 CapelliC 所添加的,\+ X \= E等于not(not(X = E))但现在具有更标准的语法。

于 2013-09-28T11:52:15.227 回答
1

好吧,为了测试,这是一个有效的:

delete_all(E, L, R) :- findall(X, (member(X, L), X \= E), R).

我认为您的代码不起作用,因为它实例化了X,然后禁止了进一步的匹配。delete /3 的文档(这就是您所追求的,只是交换参数)清楚地说明了这个问题。

你应该改变你的第一个子句

delete_all(X,[E|Tail],List):-
    \+ X \= E, !, delete_all(X,Tail,List).
于 2013-09-28T11:52:47.447 回答