How to assign meaningful names to (fresh) variables?

Hi all,

I’m trying to find a way to systematically assign meaningful names to (fresh) variables.

The structures whose variables I want to name are “metarules”. It’s not important what those are exactly (they are second-order definite clauses whose literals are enclosed in first-order terms), but I have a predicate that outputs them and this is what they look like:

?- expanded_metarules([chain], [C]).
C =  (m(chain, _460200, _460202, _460204):-m(_460200, _460216, _460218), m(_460202, _460216, _460232), m(_460204, _460232, _460218)). [1]

In [1] above, the first three variables {_460200, _460202, _460204} are second order variables that bind to predicate symbols, so I’d like to give them names that are commonly used for predicate symbols, e.g. {P,Q,R}. Remaining variables in [1] are first-order variables and they should take names that are commonly used for first-order variables, e.g. {X,Y,Z} (never minding the capitalisation).

I would like to find a way to print the metarule bound to C, above, as follows:

m(chain,P,Q,R):-m(P,X,Y),m(Q,X,Z),m(R,Z,Y) [2]

Suppose that I have a sensible way to generate appropriate atomic names for second- and first- order variables, such as {P,Q,R} and {X,Y,Z}.

I know that I can do the following:

?- expanded_metarules([chain], [_C]), term_variables(_C, [A,B,C,D,E,F]), write_term(_C, [nl(true), variable_names(['P'=A,'Q'=B,'R'=C,'X'=D,'Y'=E,'Z'=F])]). [3]
m(chain,P,Q,R):-m(P,X,Y),m(Q,X,Z),m(R,Z,Y)
true.

The query in [3] assigns variable names [A,B,C,D,E,F] to the variables in C and then prints them out replaced by the atomic variable names [‘P’,‘Q’,‘R’,‘X’,‘Y’,‘Z’] thanks to the variable_names/1 option.

However, this will only work for my purposes if I know the number of variables in a metarule, such as C, and that is not always the case. More to the point, I’d like to be able to assign arbitrary variable names to the variables in C, before I call write_term/2. Or in other words, I’d like to generate the list of variable names [A,B,C,D,E,F] “on the fly” and according to the number of variables in C.

I tried to be sneaky and call numbervars/1 on the output of term_variables/2 but that doesn’t quite work. I’m omitting the output to reduce clutter. I had a look in the other predicatesin library(varnumbers) but there doesn’t seem to be anything in there that I can use (I use that library a lot but not this time).

So, is it possible to do what I want?

Cheers,
Stassa

1 Like

See: Expandable text sections

I assume you already understands this only makes sense if you want to write your term to a file for later human inspection, no?

You can bind your variables to ‘$VAR’(Name), e.g.,

?- print(hello('$VAR'('P'))).
hello(P)

In general, Prolog variables have no name, except local to a term when this term is represented as Prolog source code. numbervars/1, the write_term/2 options and the above trick allow you to serialize a term with given variable names.

2 Likes

Uh. Thanks, that looks much simpler than I thought. I just have to generate the atomic names for ‘$VAR’/1 terms, then.

If variables have no name- what are the _104984 etc things shown at the top level? I assumed they were Swi-Prolog’s internal representation of a variable.

I assume you already understands this only makes sense if you want to write your term to a file for later human inspection, no?

The number of use cases for a finite program is infinite, this is well known :slight_smile:

Writing output to a file for later reuse is one use case that interests me. Another is debugging and generally inspecting the program. Metarules can get really long and they are already hard to read with automatically assigned variable names even when they’re short (like the one in my example). So I want to be able to pretty-print them at the top level. My current pretty-printing code calls numbervars/1 before handing over to write_term/2 but that gives results that are awkward to read:

?- expanded_metarules([chain], _MS), print_clauses(_MS).
m(chain,A,B,C):-m(A,D,E),m(B,D,F),m(C,F,E).
true.

This is “awkward” in the sense that it doesn’t match the notation in documentation and literature etc, so the user has to make a mental translation, say between [P,Q,R] and [A,B,C]. I for one always have to squint a bit to be sure what I’m reading makes sense. Also, [A,B,C] sound like constant names so there’s a bit of cognitive dissonance there.

1 Like

I feel like the tools cited above are sufficient to do whatever you like, but you seem like you’re missing something? If you want P,Q,R you can do that.

You can easily get all the variables of a program, loop through them and assign names to each, and print it out that way.

Thanks. Yes, I was missing the part about ‘$VAR’(‘P’). I was able to do what I wanted to do:

?- print_quantified_metarules([chain]).
(Chain) ∃.P,Q,R ∀.x,y,z: P(x,y)← Q(x,z),R(z,y)
true.
2 Likes

This post is many months latter and I did not re-read all the post but this might be of interest:

Pack evil – prolog/destructive.pl

In particular

defvar (Var:term) is det
defvar/1 allows you to declare one empty d-variable (but most of the times it is pointless).

1 Like

Interesting, thanks. I need to look into that pack more carefuly anyway :slight_smile:

In debugging order_by/2 found witness/2

For examples see: Order_by/2 examples

1 Like