如何从列表中删除所有子列表?

时间:2013-09-28 11:25:43

标签: prolog

我想从列表列表中删除包含[['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]].

为什么只删除第一个元素?可能有什么不对?

2 个答案:

答案 0 :(得分:1)

我想问题在于你的第一个术语(你正在搜索的模式)包含变量和那些变量`unify'以及扫描列表时的列表元素。传递匹配的元素后,模式中的变量将实例化为该元素中相应术语的值,以防止进一步匹配。

一种可能的解决方案是检查您的模式和元素是否为unifiable,但最终不会将它们统一起来。

这样的事情可以满足你的需求:

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)),但现在有了更标准的语法。

答案 1 :(得分: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).