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
), поэтому она никогда не может соответствовать анонимной переменной в первом списке.