我试图在prolog中从另一个列表中减去一个列表。在我的程序中,输入列表中有空格(例如[1,2,_,4])
我得到以下输出:
?- subtract([1,2,3,4],[3,4,_],L).
L = [2].
当我想要输出
时L = [1,2].
所以我的问题是如何防止空格与其他元素统一?已经坚持了一段时间。
答案 0 :(得分:1)
假设您希望忽略“空格”,您可以简单地删除每个列表的版本并计算它们的差异:
listWOblanks( [], [] ).
listWOblanks( [H|T], Tx ) :- var(H), !, listWOblanks( T, Tx ).
listWOblanks( [H|T], [H|Tx] ) :- listWOblanks( T, Tx ).
如果,当第一个列表有空白而第二个列表没有空白时,你需要结果仍然有空白,你可以修改上面的内容来添加第三个参数,告诉你是否删除了任何空格以便你可以纠正相应的差异。我相信SWI-Prolog有一个谓词,它会告诉你一个术语中是否没有变量,这样就无需修改listWOblanks。
答案 1 :(得分:0)
larsmans是正确的,_
是匿名变量,lists:subtract/3
的定义(我假设你在SWI-Prolog中使用)将会始终将它们统一到地面列表成员,因为它使用memberchk/2
定义。
如果您希望subtract
行为将变量视为基础术语,那么您可以像这样重新定义:
subtract2([], _, []) :- !.
subtract2([A|C], B, D) :-
var_memberchk(A, B), !,
subtract2(C, B, D).
subtract2([A|B], C, [A|D]) :-
subtract2(B, C, D).
请注意,此处的subtract2/3
与lists:subtract/3
的定义几乎相同(请尝试listing(subtract).
自行查看)。唯一的区别是列表成员谓词var_memberchk/2
,其定义如下:
var_memberchk(A0, [A1|_]) :-
A0 == A1, !.
var_memberchk(A0, [_|R]) :-
var_memberchk(A0, R).
这将检查变量,原子或术语是否在列表中。所以,试试这个我们得到:
?- subtract2([1,2,3,4],[3,4,_],L).
L = [1, 2].
请注意,如果我们按照您的预期命名变量,它仍然有效:
?- subtract2([1,2,A,3,B,4],[3,A,4],L).
L = [1, 2, B].
如果我们明确地给匿名变量命名,它也可以工作,如:
?- subtract2([1,2,_A,3,_B,4],[3,_A,4],L).
L = [1, 2, _B].
最后请注意,由于_
没有名称,subtract2/3
永远不会能够将其与任一列表中的其他匿名变量相匹配,例如:
subtract2([1,2,_,4],[3,_,4],L).
L = [1, 2, _G415].
其中_G415
是由第一个输入列表中的_
表示的匿名全局变量。第二个是不同的全局变量(例如_G416
),因此永远不会匹配第一个列表中的匿名变量。
答案 2 :(得分:0)
另一种方式:
% Uses list catenation to generate sublists /subtraction
conc([], L, L).
conc([X|L1], L2, [X|L3]) :-
conc(L1, L2, L3).
% Finds all list members that have values and then
% use list catenation to generate the sublists
subtract(L1, L2, L3) :-
findall(D, (nth0(N, L2, D), nonvar(D)), PureL2),
conc(L3, PureL2, L1).
这假设只有一个列表有'_',但如果两个列表都有相同的问题,你可以为L1做同样的findall。