Named singleton variables

Hi!

I’d like to know if there’s some way to detect Named singleton variables (i.e. variables starting with a double underscore (__) or a single underscore followed by an uppercase letter, e.g., __var or _Var, Section 2.15.1.10 of the manual).

I’ve seen read_term can inform the list of singleton variables but that’s not exactly what I’m looking for. For example in:

append([1,2,3],[a,b,c],_U), append(_U,[[b,1],[s,6]],A).

_U is a named singleton variable but it is not a singleton variable.

Thanks for the help.

Cheers!

Yeah the underscore is quite handy. Take this example (*):

/* What are the last 8 digits of fib(1000000) */

?- fib(1000000, _X), Y is _X mod 10^8.
Y = 42546875.

_X would be huge, but as a marked variable it gets suppressed.

If you read such a query, you see all variables in variable_names/1:

?- read_term(T, [variable_names(L)]).
fib(1000000, _X), Y is _X mod 10^8.
T = (fib(1000000, _A), _B is _A mod 10^8),
L = ['_X'=_A, 'Y'=_B].

(*) Can you do it? Grok and DeepSeek failed, ChatGPT could do it.

That’s exactly why I want access to those variables. I can write a piece of code based on variable_names but I thought there would some standard predicate doing the job.

In SWI-Prolog the thing is controlled by toplevel_print_anon:

?- append([1,2],[3,4],_X), append(_X,[5,6],Y).
Y = [1, 2, 3, 4, 5, 6].

?- set_prolog_flag(toplevel_print_anon, true).
true.

?- append([1,2],[3,4],_X), append(_X,[5,6],Y).
_X = [1, 2, 3, 4],
Y = [1, 2, 3, 4, 5, 6].

I was just currious which piece of code uses this flag:

hide_names([Name|T0], Skel, Subst, T) :-
    (   sub_atom(Name, 0, _, _, '_'),
        current_prolog_flag(toplevel_print_anon, false),
        sub_atom(Name, 1, 1, _, Next),
        char_type(Next, prolog_var_start)
    ->  true
    ;   Subst == [],
        Skel == '$VAR'(Name)
    ),
    !,
    hide_names(T0, Skel, Subst, T).

In the SWI-Prolog file toplevel.pl. So it uses sub_atom/4, and hard
coded ‘_’ to detect marked variables. Instead you could also use a certain
Unicode class. Don’t know how common this is, it would extend the

notion of underscore, like using Pc from Unicode.

1 Like

Good to know. Thanks!

The consult routine implements a different check, it doesn’t
use prolog_var_start for the second character, which would
be underscore+upper. It has a variety of checks since it also

looks for multitons and rather suppresses digit+upper:

warn_singleton(const char *name)	/* Name in UTF-8 */
{ if ( name[0] != '_' )			/* not _*: always warn */
    return true;
  if ( name[1] == '_' )			/* __*: never warn */
    return false;
  if ( name[1] )			/* _a: warn */
  { int c;

    utf8_get_char(&name[1], &c);
    if ( isDigitW(c) )
      return false;
    if ( !PlUpperW(c) )
      return true;
  }
  return false;
}

This means for example a variable _12 is not suppressed in
queries according to the Prolog code hide_names/4, like for
example here:

/* SWI-Prolog 9.3.22 */
?- append([1],[2],_12), append(_12,[3],Y).
_12 = [1, 2],
Y = [1, 2, 3].

On the other hand _12 is suppressed from singleton check when
consulted, and interestingly also not multiton checked.This passes
without warning, was testing with SWI-Prolog 9.3.22 again:

/* currrently implemented */
test(_12).
test(_12, _12).

The documentation about marked variables is a little bit outdated,
since it gives underscore followed by a digit as singleton checked,
but this is currently not the case during consult:

/* outdated documentation */
test(_12).	Singleton variables: [_12]

https://www.swi-prolog.org/pldoc/man?section=singleton

Thanks. Fixed (commit 8d9b23a2ee5858af086dd70601dc452a7f85bf19)

That is a nice opportunity to create your first PR :slight_smile: And yes, I agree the text is now a bit awkward, so I’ll accept an improved version …