How does one check a list for _?

In needing a set type (think has_type/2) that is more rigours than ordered list, e.g. list_to_set/2, the list must not allow the use of _.

How does one check a list for _?


Details (Click triangle to expand)

In other words with creating a set from a list (list_to_set/2) this is acceptable

?- list_to_set([a],Set).
Set = [a].

?- list_to_set([a,a],Set).
Set = [a].

?- list_to_set([a,A],Set).
Set = [a, A].

?- list_to_set([A,A],Set).
Set = [A].

but this is not

?- list_to_set([_,_],Set).
Set = [_, _].

Thus an enhanced form of list_to_set/2 is needed for my case.

I am not asking for or abdicating that list_to_set/2 be modified in the SWI-Prolog system, my case just needs an additional guard for the type check to fail when a list has any _ in it.


Personal notes (Click triangle to expand)

Prolog has some predicates for revealing properties of an entity. These predicates usually have the name property in them. There is one for variables, i.e. var_property/2.

Thus using var_property/2 was tried.

?- var_property(_,P).
P = fresh(true) ;
false.

?- var_property(A,P).
P = fresh(true) ;
false.

however it did not uniquely identify a _ variable.


After reading reply from Jan W. tired.

?- ?=(_,_).
false.

?- ?=(A,A).
true.

?- ?=(_a,_a).
true.

?- ?=(__a,__a).
true.

which reveals a means of checking for a difference in the kinds of variables.


To see the internal representation of a list with _ write_term/2 can be used.

?- L = [_,_,a,A,_a,_A,__a,__A], write_term(L,[]).
[_2708,_2714,a,_2726,_2732,_2738,_2744,_2750]
L = [_, _, a, A, _a, _A, __a, __A].


After seeing reply from Jan W.

My concern for two _ in a list converted to a set is unwarranted, the variables are different, e.g.

?- list_to_set([_,_],Set),write_term(Set,[]).
[_5734,_5740]
Set = [_, _]

as it is the internal representation that matters not the user friendly representation.

In Prolog you only have variables that maybe different or aliased. _ is just a concept of read_term/2 which makes variables that have the same name be the same variable except for _, which produces a new variable for every occurrence.

So, [_|_] is exactly the same as [_1, _2] (using numeric syntax to avoid the discussion about singleton/multiton).

list_to_set/2, like sort/2 and the ord_* predicates all compare terms based on the standard order of terms. This means that only terms that compare equal under ==/2 are removed. Further instantiation of elements may cause more elements to become equal under ==/2 unless ?=/2 is true for all pairs of the set. ?=/2 is true if the two arguments are equal or can never become equal.

1 Like

I think what you’re looking for is a verification that no two items in the list can ever be instantiated in such a way that their ordering changes (e.g., they currently do not compare equal under ==/2 but could unify with =/2).

You might be interestested in the Special unification and comparison predicates and also in \+ \+ X=Y.