将条款转换为原子,在YAP prolog中保留变量名称

Ser*_*gio 4 prolog

有没有办法配置YAP(和/或SWI prolog),以便它们在任何调用term_to_atom/2?中保留变量名称.

例如,当我执行此操作时:

term_to_atom(member(X, [1,2]), A).
Run Code Online (Sandbox Code Playgroud)

我得到了这个答案:

A = 'member(_131405,[1,2])'
Run Code Online (Sandbox Code Playgroud)

哪里X被其内部代表所取代.

但是,我想得到这个答案:

A = 'member(X,[1,2])'
Run Code Online (Sandbox Code Playgroud)

谢谢你的帮助!

fal*_*lse 11

涉及两个问题.如何将变量名称X放入系统,以及如何将具有此类变量的术语放入原子中.

X你输入是通过将它转换为不具有关联的名称的常规变量顶层读取.让我们在YAP中看到:

   ?- read(Term).
   |: X+3*Y+X.
Term = _A+3*_B+_A
Run Code Online (Sandbox Code Playgroud)

|:是YAP的提示输入.我们已输入X+3*Y+X. 但是,变量Term包含_A_B(由顶级选择的名称)代替XY.因此,一旦读取/ 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
Run Code Online (Sandbox Code Playgroud)

因此,read选项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).
Run Code Online (Sandbox Code Playgroud)

这么多的阅读.

现在写作.我们不能直接写这个术语,但必须随附列表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'.
Run Code Online (Sandbox Code Playgroud)

变量_131284看起来非常难看.要获取与其名称相关联的变量以进行打印,我们可以实现term_to_atom/3如下:

term_to_atom(T, Eqs, A) :-
   with_output_to(atom(A), write_term(T,[variable_names(Eqs),quoted(true)]) ).
Run Code Online (Sandbox Code Playgroud)

并像这样使用它:

   ?- 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
Run Code Online (Sandbox Code Playgroud)

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).
Run Code Online (Sandbox Code Playgroud)

以下是针对6.3.4之前的YAP的ISO不兼容的解决方案.它不再是必要的.至于与单独写入选项的差异: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) ).
Run Code Online (Sandbox Code Playgroud)

对于SWI,您必须替换atom_codes(N,Chs)N = Ch.并library(lambda)先安装.它已预先安装在YAP中.