Для длины /2, как добавить понятные человеку имена переменных

Как могут отображаться понятные человеку имена переменных для имен переменных, генерируемых системой?

В качестве простого примера:

?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [_5112],
N = 1 ;
Ls = [_5112, _5118],
N = 2 ;
Ls = [_5112, _5118, _5124],
N = 3

было бы лучше, как

?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [a],
N = 1 ;
Ls = [a, b],
N = 2 ;
Ls = [a, b, c],
N = 3 

отображение

_5112 = a
_5118 = b
_5124 = c

подробности

Самое близкое решение, которое я нашел, использует read_term / 2, как показано в этом ответе с variable_names(Vars) вариант, однако моя проблема не использует read_term чтобы получить термин из консоли.

Если это дубликат, дайте мне знать; Я не мог найти один.


Настоящая проблема основана на генерации данных тестового примера:

?- 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],
...

Смотрите это и это для list_partitionedNU/2,


Следите за ответами.

Основано на ответе Уильяма

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]] ;
...

Основано на ответе 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]] ;
...

3 ответа

Решение

Мы можем создать предикат, который "присваивает" значения переменным в функторе в рекурсивном режиме, с помощью аккумулятора, который отслеживает последнее назначенное "имя".

Например:

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).

Например:

?- 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] .

Таким образом, мы "проходим" по дереву и присваиваем значения переменным. С помощью приведенной выше реализации мы не учитываем существующие константы. Таким образом, мы можем присвоить значения, которые уже существуют, переменным. Кроме того, мы просто продолжаем увеличивать код символа, поэтому в конечном итоге мы получим символы, управляющие символы и символы.

Однако вышеперечисленные недостатки можно "устранить", сначала проверив функтор и получив список констант, которые нужно пропустить. Кроме того, генератор терминов, конечно, может быть улучшен, например, путем aa после z,

@DanielLyons указал на term_variables/2 предикат, который может облегчить assign/1 много предикатов, как:

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).

Это, конечно, все еще не решает вышеуказанные недостатки, хотя, как уже было сказано, мы можем решить их, используя что-то еще, кроме char_code чтобы получить имя константы, и сначала сделав пробуждение, чтобы найти используемые константы.

Давайте не будем забывать очевидный вариант: другой процессор Prolog.

Использование SICStus Prolog 4.5.0 ( попробуйте полнофункциональный SICStus Prolog 30 дней бесплатно):

|? - Xs = [_C, f (_E) | _], длина (Xs,N).
N = 2, Xs = [_C,f(_E)]?;
N = 3, Xs = [_C,f(_E),_A]?;
N = 4, Xs = [_C,f(_E),_A,_B]?;
N = 5, Xs = [_C,f(_E),_A,_B,_D]?;
N = 6, Xs = [_C,f(_E),_A,_B,_D,_F]?;
N = 7, Xs = [_C,f(_E),_A,_B,_D,_F,_G]? ...

Старые, но золотые номера vars / 3 были пересмотрены:

?- length(L,5),numbervars(L,0,N).
L = [A, B, C, D, E],
N = 5.

не уверен, что это действительно полезно, но приятно исследовать...

?- length(L,5),numbervars(L,0'a,N).
L = [T3, U3, V3, W3, X3],
N = 102.
Другие вопросы по тегам