Преобразование терминов в атомы с сохранением имен переменных в прологе YAP

Есть ли способ настроить YAP (и / или пролог SWI), чтобы они сохраняли имена переменных при любом вызове term_to_atom/2?.

Например, когда я выполняю это:

term_to_atom(member(X, [1,2]), A).

Я получаю этот ответ:

A = 'member(_131405,[1,2])'

куда X был заменен его внутренним представлением.

Тем не менее, я хотел бы получить этот ответ вместо:

A = 'member(X,[1,2])'

Спасибо за любую помощь!

1 ответ

Решение

Есть две проблемы. Как получить имя переменной X в систему, и как получить термин с такой переменной в атом.

X вводимый вами текст читается верхним уровнем, который преобразует его в обычную переменную, с которой не связано имя. Давайте посмотрим, что в YAP:

   ?- read(Term).
   |: X+3*Y+X.
Term = _A+3*_B+_A

|: подсказка YAP для ввода. И мы вошли X+3*Y+X. Тем не менее, переменная Term содержит _A а также _B (имена, выбранные на верхнем уровне) вместо X а также Y, Таким образом, информация теряется и не может быть восстановлена ​​после прочтения read/1.

Вы должны получить доступ к этой информации по-другому с более общей встроенной для чтения read_term/2,3 и вариант variable_names/1,

   ?- read_term(T,[variable_names(Eqs)]).
   |: X+3*Y+X.
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A

Так что вариант чтения variable_names/1 дает вам информацию для восстановления имен переменных. Для каждой именованной переменной читается read_term/2 есть структура Name = Variable где Name - это атом, представляющий имя переменной. Выше, 'X' это заглавная буква X.

Анонимные переменные, то есть переменные, чье имя _, не встречаются в списке имен переменных. Они могут быть быстро извлечены следующим образом:

 ?- read_term(T,[variable_names(Eqs)]),
    term_variables(Eqs, Named),
    term_variables(Named+T, Vars),
    append(Named, Anons, Vars).

Так много для чтения.

Теперь для написания. Мы не можем написать термин напрямую, но должны сопровождать его списком Eqs, Давайте назовем новый предикат term_to_atom(Term, Eqs, Atom), И в YAP, и в SWI есть with_output_to(Output, Goal) который пишет вывод Goal в разные направления, такие как atom(A), Так что теперь вы можете использовать write_term/2, чтобы написать термин как вам угодно. Пример:

?- with_output_to(atom(A),write_term('a b'+X,[quoted(true)])).
A = '\'a b\'+_131284'.

Переменная _131284 выглядит очень некрасиво. Чтобы получить переменные, связанные с их именами для печати, мы можем реализовать term_to_atom/3 следующее:

term_to_atom(T, Eqs, A) :-
   with_output_to(atom(A), write_term(T,[variable_names(Eqs),quoted(true)]) ).

И используйте это так:

   ?- read_term(T,[variable_names(Eqs)]), term_to_atom(T, Eqs, Atom).
   |: X+3*Y+X.
Atom = 'X+3*Y+X',
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A

variable_names/1 существует как опция записи в ISO, Minerva, Jekejeke, GNU, B, SWI, YAP и SICStus.

В SICStus, создателе записи терминов в списки, пишется:

:- use_module(library(codesio)).

term_to_atom(T, Eqs, Atom) :-
   write_term_to_codes(T, Codes, [variable_names(Eqs),quoted(true)]),
   atom_codes(Atom, Codes).

Следующее было несовместимым с ISO обходным путем для YAP до 6.3.4. Это больше не нужно. Что касается различий для отдельной опции записи: term_to_atom/3 как определено ниже, мешает ограничениям и неправильно отображает '$VAR'/1,

Но на данный момент мы можем только приблизить идеальный вариант variable_names/1, Чтобы напечатать термины с нашими собственными именами переменных, переменные в YAP должны быть заменены на '$VAR'(Codes) где Codes список кодов символов Это не совсем то же самое, но это очень близко. Это входит в файл:

:- use_module(library(apply)).
:- use_module(library(lambda)).

write_eqs_term(T, Eqs) :-
   \+ \+ ( 
           maplist(\Eq^( Eq = (N='$VAR'(Chs)), atom_codes(N,Chs)), Eqs),
           write_term(T,[numbervars(true),quoted(true)])
   ).

term_to_atom(T, Eqs, A) :-
   with_output_to(atom(A), write_eqs_term(T, Eqs) ).

Для SWI вам придется заменить atom_codes(N,Chs) от N = Ch, и установить library(lambda) первый. Он предварительно установлен в YAP.

Другие вопросы по тегам