13

What is the most compact and canonical way in ISO Prolog to test for a list of distinct variables? Let's call this meta-logical predicate is_varset/1.

So it should succeed if its argument is a list of variables that are all different. Note that a list always contains a [] at its end. If a variable is at the end, we call this a partial list (which is thus not a list). And if a non-variable term occurs as a suffix that is neither [] nor a variable, then this is neither a partial list nor a list.

A notable special case of a term being neither a partial list nor a list are infinite lists. They contain at least two suffixes that are identical, actually they then possess infinitely such suffixes. Infinite lists are out of scope of the standard — all attempts to create them result in a STO unification whose result is undefined. Still, some systems support them, so ideally for those infinite lists, is_varset/1 should fail finitely.

?- is_varset([A|nonlist]).
false.

?- is_varset([A,B]), is_varset([B,A]).
true.

?- is_varset([A,B,A]).
false.

?- is_varset([A,f(B)]).
false.

?- is_varset([A|_]).
false.

?- L = [_|L], is_varset(L).  % may loop, should rather terminate
false.

Here is an overview of the built-ins in ISO/IEC 13211-1:1995 including Cor.2:2012.

false
  • 10,264
  • 13
  • 101
  • 209

1 Answers1

8

this simple definition in SWI-Prolog seems to accomplish the requirements

is_varset(Vs) :- /*is_list(Vs),*/ term_variables(Vs, T), T == Vs.
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • 2
    Looks nice! Could you justify why you do not put a `=` in place of `==`? – false Dec 29 '14 at 12:19
  • 2
    this test case `?- is_varset([A,f(B)]).` It answers `B = f(B).` when using (=)/2. Admittedly, I've used (==)/2 in first place just based on intuition, and tested again after your comment... – CapelliC Dec 29 '14 at 12:36
  • 2
    And what if `unify_with_occurs_check` is used in place of `==`? – false Dec 29 '14 at 13:08
  • 2
    logically works, I think it could trash the trail... but I don't know enough of the inner workings to push this hypothesis any further... – CapelliC Dec 29 '14 at 13:46
  • 2
    "trashing the trail", that's some performance feature. But otherwise, can't it happen that upon success variables are instantiated? – false Dec 29 '14 at 14:00
  • 1
    I have a low level 'mental model' of variables, since I wrote by myself a Prolog time ago, based on sharing cells from allocation heap. Not sure if variables *sharing* counts for instantiated. I would say that yes, variables in Vs get instantiated, or better, shared with fresh, unbound variables allocated by term_variables. With (==)/2 they remain free – CapelliC Dec 29 '14 at 14:34
  • 1
    That is not instantiating - when seen from `is_varset(L)`. And: In some implementations of `==` (internally), subterms of one term might all point to the other upon success. And even better: `term_variables(T,Vs)` might `T = Vs` should `T` be `==` `Vs`. – false Dec 29 '14 at 15:49