27

I was testing my new version of SWI prolog and keep coming across the error :singleton variable.

Example:

member(X,[X|T]).

member(X,[X|T]) :- member(X,T).

finds the member of a list such as :

member(yolands,[yolanda,tim])

X = yes

but instead I get a singleton variables error for X and T

if I do the following:

member(X,[X|_]).
member(X,[_|T]) :- member(X,T).

It works but looks ugly!

Can anyone explain why single variables ar enot allowed and if this ANSI standard?

Timothy Lawman
  • 2,194
  • 6
  • 24
  • 33

4 Answers4

14

Singleton variables are useless in Prolog, and are easily introduced by editing typos.

The warning is welcome to me, as it allows to easily spot such frequent cause of error.

Being a warning, you can run code containing singletons, but any value these eventually will assume will be lost.

I don't think that ISO standard (never heard about ANSI) forbids such variables.

You could rewrite your example in this way

member(X, [Y|T]) :- X = Y ; member(X, T).

and then forget about the singleton.

CapelliC
  • 59,646
  • 5
  • 47
  • 90
11

You have a bug here:

member(X,[X|T]) :- member(X,T).

What you're actually saying (as opposed to what you think you're saying) is that member/2 holds if X is at the head of the list and present in the tail of the list. This predicate will only ever be true for the first N copies of the same thing at the beginning of a list, so it's a very strange thing to say!

?- member(X, [a,a,c]).
X = a ;
X = a ;
false.

?- member(X, [b,a,a]).
X = b ;
false.

Now, you could correct the bug and still have a singleton warning by doing something like this:

member(X, [Y|T]) :- member(X, T).

But this is neither as good as the conventional definition with two heads or @CapelliC's version (+1) with an explicit OR. I think you should wait until you understand Prolog a little better before putting much stock in your sense of Prolog code aesthetics. If you stick with it for a while you'll come to appreciate this warning as well as the use of anonymous variables.

What makes singleton variables useless in Prolog is that they're named but nothing is known about them and they have no effect on the rest of the computation. The underscore highlights that absolutely anything could go in there without affecting the meaning. What makes

member(X, [X|T]).

true is that the X is position 1 is the same as the X at the head of the list in position 2. Lists must either be empty or have a head and a tail, but what's in the tail is not relevant here, what matters is that X is also the head. The T could be the rest of the list, or it could be an improper list, or it could be a breadbox or lightning or the smell of the air on a spring day. It has no bearing on the truth of member(X, [X|T]).

The singleton warning tells you "you've reserved a name for something here, but you never call anything by that name." The first thing I do when I get this message and it isn't an obvious typo is replace the name with _ and see if my code still makes sense. If it doesn't, I have a logic error. If it does, it was probably unnecessary.

Daniel Lyons
  • 22,421
  • 2
  • 50
  • 77
  • nice catch (+1): actually the bug was in the clause *without* singleton! – CapelliC Mar 14 '13 at 21:00
  • What do you meant with "CapelliC's version (+1) with an explicit OR": where is that OR in his clause? – Bento Oct 05 '15 at 21:35
  • @Bento the `;` is an explicit OR in Prolog. – Daniel Lyons Oct 05 '15 at 21:35
  • I imagined that (infact "," is AND), but looking at the site LearnPrologNow some minutes ago (I'm litterally new to the Prolog language practice, but at least I know the theory) I have found no specifications for ";" syntax so I thought Capelli had an oversight. Now I know it was not the case :-) (incidentally I have found your answer very very useful for a problem I posed here in Edit2: http://stackoverflow.com/questions/32942127/sorting-program-for-swi-prolog) – Bento Oct 05 '15 at 22:23
  • just a little question: which is the theoretic counterpart of that OR? Is that a bipartition of the ";" clause mantaining the same head and distributing the two atoms ? – Bento Oct 05 '15 at 22:34
  • I think however it is not equivalent from a logical point of view (the single clause does not implies the two clauses) – Bento Oct 05 '15 at 22:47
  • I have no idea what you're talking about. There is an operational difference that makes the literal `;` more desirable: it eliminates an unnecessary choice point. If that's what you're talking about then yes, but I think logically (in contrast to Prolog's operational semantics) it is the same. Unfortunately, we do have to make choices when we decide to execute code on an actual machine though. :) – Daniel Lyons Oct 05 '15 at 22:49
  • okay, I think (not quite sure..) you have hit the mark.. infact two clauses are less desirable than one – Bento Oct 05 '15 at 23:08
9

You can read about it on the official page of SWI-Prolog FAQ

The most common cases this warning appears are:

  1. Spelling mistakes in variables
  2. Forget to use/bind a variable

SWI suggest some ways to ignore it:

  1. Use anonymous variable named _ for this purpose.
  2. Use your variable starting with _ (like _T, _X), to avoid warning and document what you ignore.
  3. If you are aware of what you are doing, you can use :- style_check(-singleton). and all warnings should go away.
Olexiy Pyvovarov
  • 870
  • 2
  • 17
  • 32
0

This is an example from Learn Prolog Now! (p 31). It produced the error message 'Singleton variables:...'

vertical(line(point(X,Y),point(X,Z))). 
horizontal(line(point(X,Y),point(Z,Y))).

Replacing [Y,Z] in vertical/1 and [X,Z] in horizontal/1 with anonymous variable _ got rid of the error message.

vertical(line(point(X,_),point(X,_))).
horizontal(line(point(_,Y),point(_,Y))).

Thank you everyone.

Antypas
  • 1
  • 2