How can human readable variable names be displayed for system generated variable names?
As a simple example:
?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [_5112],
N = 1 ;
Ls = [_5112, _5118],
N = 2 ;
Ls = [_5112, _5118, _5124],
N = 3
would be nicer as
?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [a],
N = 1 ;
Ls = [a, b],
N = 2 ;
Ls = [a, b, c],
N = 3
mapping
_5112 = a
_5118 = b
_5124 = c
Details
The closest solution I found uses read_term/2 as demonstrated in this answer with the variable_names(Vars)
option, however my problem does not use read_term
to get the term from the console.
If this is a duplicate let me know; I could not find one.
The real problem is based on generating test case data:
?- length(Ls,N),list_partitionedNU(Ls,Ps).
Ls = Ps, Ps = [],
N = 0 ;
Ls = [_5242],
N = 1,
Ps = [[_5242]] ;
Ls = [_5242, _5248],
N = 2,
Ps = [[_5242], [_5248]] ;
Ls = [_5242, _5248],
N = 2,
Ps = [[_5242, _5248]] ;
Ls = [_5242, _5248, _5254],
...
See this and this for list_partitionedNU/2
.
Follow up after answers.
Based on answer by William
partitions(Ps) :-
length(Ls,N),
assign(Ls),
list_partitionedNU(Ls,Ps).
?- partitions(Ps).
Ps = [] ;
Ps = [[a]] ;
Ps = [[a], [b]] ;
Ps = [[a, b]] ;
Ps = [[a], [b], [c]] ;
Ps = [[a], [b, c]] ;
Ps = [[a, b], [c]] ;
Ps = [[a, c], [b]] ;
Ps = [[a, b, c]] ;
Ps = [[a], [b], [c], [d]] ;
Ps = [[a], [b], [c, d]] ;
Ps = [[a], [b, c], [d]] ;
Ps = [[a], [b, d], [c]] ;
Ps = [[a], [b, c, d]] ;
Ps = [[a, b], [c], [d]] ;
Ps = [[a, c], [b], [d]] ;
Ps = [[a, d], [b], [c]] ;
Ps = [[a, b], [c, d]] ;
Ps = [[a, c], [b, d]] ;
Ps = [[a, d], [b, c]] ;
Ps = [[a, b, c], [d]] ;
Ps = [[a, b, d], [c]] ;
Ps = [[a, c, d], [b]] ;
Ps = [[a, b, c, d]] ;
...
Based on answer by CapelliC
partitions(Ps) :-
length(Ls,N),
numbervars(Ls,0,N),
list_partitionedNU(Ls,Ps).
?- partitions(Ps).
Ps = [] ;
Ps = [[A]] ;
Ps = [[A], [B]] ;
Ps = [[A, B]] ;
Ps = [[A], [B], [C]] ;
Ps = [[A], [B, C]] ;
Ps = [[A, B], [C]] ;
Ps = [[A, C], [B]] ;
Ps = [[A, B, C]] ;
Ps = [[A], [B], [C], [D]] ;
Ps = [[A], [B], [C, D]] ;
Ps = [[A], [B, C], [D]] ;
Ps = [[A], [B, D], [C]] ;
Ps = [[A], [B, C, D]] ;
Ps = [[A, B], [C], [D]] ;
Ps = [[A, C], [B], [D]] ;
Ps = [[A, D], [B], [C]] ;
Ps = [[A, B], [C, D]] ;
Ps = [[A, C], [B, D]] ;
Ps = [[A, D], [B, C]] ;
Ps = [[A, B, C], [D]] ;
Ps = [[A, B, D], [C]] ;
Ps = [[A, C, D], [B]] ;
Ps = [[A, B, C, D]] ;
...
We can construct a predicate that "assigns" values to the variables in a functor in a recursive fasion, with an accumulator that keeps track of the latest "name" assigned.
For example:
assign(Term) :-
assign(Term, 97, _).
assign(X, N, N1) :-
var(X),
!,
char_code(X, N),
N1 is N+1.
assign(F, N, N1) :-
F =.. [_|A],
assign_list(A, N, N1).
assign_list([], N, N).
assign_list([H|T], N, NT) :-
assign(H, N, N1),
assign_list(T, N1, NT).
For example:
?- length(L, _), assign(L).
L = [] ;
L = [a] ;
L = [a, b] ;
L = [a, b, c] ;
L = [a, b, c, d] ;
L = [a, b, c, d, e] ;
L = [a, b, c, d, e, f] .
?- Q = [L, [_, _]], length(L, _), assign(Q).
Q = [[], [a, b]],
L = [] ;
Q = [[a], [b, c]],
L = [a] ;
Q = [[a, b], [c, d]],
L = [a, b] ;
Q = [[a, b, c], [d, e]],
L = [a, b, c] .
We thus "walk" through the tree and assign values to the variables. With the above implementation we do not take into account existing constants. So we might assign values that already exist to the variables. Furthermore we just keep incrementing the character code, so eventually we will reach symbols, control characters, and characters.
The above shortcomings can however be "solved" by first inspecting the functor and obtaining a list of constants to skip. Furthermore the generator of terms can of course be improved, for example by yielding aa
after z
.
@DanielLyons pointed to the term_variables/2
predicate, which can ease the assign/1
predicate a lot, like:
assign(Term) :-
term_variables(Term, Vars),
assign_list(Vars, 97).
assign_list([], _).
assign_list([H|T], N) :-
char_code(H, N),
N1 is N+1,
assign_list(T, N1).
This of course still does not solves the above stated shortcomings, although, as said, we can solve these by using something else than char_code
to obtain a constant name, and by first making a wak to look for constants in use.