Преобразование терминов в атомы с сохранением имен переменных в прологе 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.