Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
209 views
in Technique[技术] by (71.8m points)

Converting Terms to Atoms preserving variable names in YAP prolog

Is there a way to configure YAP (and/or SWI prolog) so they will preserve variable names in any call to term_to_atom/2 ?.

For example, when I execute this:

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

I obtain this answer:

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

Where X has been replaced by its internal representation.

However, I would like to get this answer instead:

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

Thanks for any help!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

There are two issues involved. How to get the variable name X into the system, and how to get a term with such a variable into the atom.

The X you type in is read by the top level which converts it to a regular variable which does not have a name associated. Let's see that in YAP:

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

The |: is YAP's prompt for input. And we have entered X+3*Y+X. However, the variable Term contains _A and _B (names chosen by the top level) in place of X and Y. So the information is lost and cannot be restored once it is read by read/1.

You have to access that information differently with the more general built-in for reading read_term/2,3 and the option variable_names/1.

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

So the read option variable_names/1 gives you the information to restore the variable names. For each named variable read by read_term/2 there is a structure Name = Variable where Name is an atom representing the variable name. Above, 'X' is the name capital X.

Anonymous variables, that is variables whose name is _, do not occur in the list of variable names. They can be rapidly extracted like so:

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

So much for the reading.

Now for the writing. We cannot write the term directly but have to accompany it with the list Eqs. Let's call the new predicate term_to_atom(Term, Eqs, Atom). In both YAP and SWI there is with_output_to(Output, Goal) which writes the output of Goal to different destinations like atom(A). So you can now use write_term/2 to write the term as you please. An example:

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

The variable _131284 looks very ugly. To get variables associated with their names for printing we can implement term_to_atom/3 as follows:

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

And use it like so:

   ?- 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 exists as a write option in ISO, Minerva, Jekejeke, GNU, B, SWI, YAP, and SICStus.

In SICStus, the originator of writing terms to lists, one writes:

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

The following was an ISO incompatible work around for YAP prior to 6.3.4. It is no longer necessary. As for the differences to a separate write option: term_to_atom/3 as defined below interferes with constraints and does not correctly render '$VAR'/1.

But for the moment we can only approximate the ideal option variable_names/1. To print terms with our own variable names, variables have to be substituted in YAP by '$VAR'(Codes) where Codes is a list of character codes. This does not do exactly the same, but it is very close. This goes into a file:

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

For SWI, you would have to replace atom_codes(N,Chs) by N = Ch. and install library(lambda) first. It's pre-installed in YAP.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...