是否有一个函数可以在不统一变量的情况下检查变量是否是列表的成员?

Is there a function that checks if a variable is a member of a list without unifying it?

我想在我的 cod 中实现一个谓词来查找包含某个元素的所有列表,在我的例子中,该元素是一个变量,例如 P3。 问题是使用谓词成员不起作用,因为它一直将变量与列表的元素统一起来:

?- member(P3, [P1,P3]). P3 = P1 ; true.

我希望它 return 正确,因为 P3 是列表的成员,而不是因为 P1 是。 有没有办法让我检查变量 P3 是否是列表的成员而不统一它? 谢谢

在Prolog中,一个变量只能与一个值统一一次。因此,如果变量 V 可以与 this 统一并且变量 W 可以与 that 统一,那么这些变量是不同的(否则,它们是同一个变量)。

samevar(V, W) :- var(V), var(W), not((V=this, W=that)).

这里有一些例子:

?- samevar(A,B).
false.

?- samevar(A,A).
true.

使用samevar/2,我们可以定义如下谓词:

varmember(V, [W|_]) :- samevar(V, W).
varmember(V, [_|T]) :- varmember(V, T).

这里有一些例子:

?- varmember(a, [V1, a, V3, V4, V5]).
false.

?- varmember(V2, [V1, V3, V4, V5]).
false.

?- varmember(V2, [V1, V2, V3, V4, V5]).
true ;
false.

?- varmember(V2, [V1, V2, V3, V2, V4, V5]).
true ;
true ;
false.

?- varmember(V2, [V1, V2, V3, V2, V4, V2, V5]).
true ;
true ;
true ;
false.

?- varmember(V2, [this, V2, that, V2, V3, V4, V5]).
true ;
true ;
false.

(==)/2 可以满足您的要求。

@Term1 == @Term2
True if Term1 is equivalent to Term2. A variable is only identical to a sharing variable.

?- X == Y.
false.

?- X=a, Y=b, X == Y.
false.

?- X=a, Y=a, X == Y.
X = Y, Y = a.

所以你可以把它实现为

membersame(X, [A|_]) :-
    X == A.
membersame(X, [_|Rest]) :-
    membersame(X, Rest).

或者您也可以使用 member/2 对列表进行隐式迭代并使用 (==)/2 进行限制(感谢@TA_intern)。

membersame(X, Xs) :-
    member(Y, Xs), X == Y.

示例:

?- membersame(X, [A, B, C, X, a, b, c]).
true ;
false.

?- membersame(X, [A, B, C, a, b, c]).
false.