列表只是穿着华丽服装的术语。
-
[] 是一个简单的原子。
-
[a] 是术语 .(a,[]) 的语法糖
-
[a,b] 是术语 .(a,.(b,[])) 的语法糖。
-
[H|T] 是术语 .(H,T) 的语法糖
仅此而已。保留括号和句点,确实如此。
因此,您所说的实际上与列表无关,而是与术语有关。如果所讨论的术语是完全绑定的——意味着它以及递归地任何子术语不包含任何非统一变量,则该术语是不可变的。但如果它包含任何未绑定的变量,它就是可变的。
所以,您所说的是执行递归树遍历来克隆一个术语,用新副本替换任何未绑定的变量。诀窍是您需要映射遇到的每个变量及其替换。所以像 [A,A,B,B,foo(A,B,C),C] 这样的东西会以 [X,X,Y,Y,foo(X,Y,Z),Z] 和 not [V1,V2,V3,V4,foo(V5,V6,V7),V8] 出现。
幸运的是,Prolog 带有内置工具:copy_term/2。
但我想你的导师并不是要你使用它。
遍历任意项并不困难。类似这样的东西(目前没有方便的 Prolog):
clone_deep( T , C ) :- clone_deep( T, [], C, _ ).
% T: source term
% S: symbol table
% C: cloned term
% S1: [possibly] extended symbol table
clone_deep( T , S , C, S1 ) :-
var(T), % term is a variable
map_var(T,S,C,S1) % fetch/add its mapping to the symbol table.
.
clone_deep( T , S , T , S ) :-
atomic(T) % term is atomic (number, atom, etc.)
.
clone_deep( T , S , C, S1 ) :-
compound(T), % term is a compound term like foo() or foo(X,Y).
T =.. [Functor|Args], % decompose it into its functor and its argument list
clone_deep(Args,S,Args1,S1), % recursively clone its arguments
C =.. [Functor|Args1] % recompose the new compound term
.
% recursively run down the list of symbol mappings to find the self-same variable
% add it if not found.
map_var( V , [ X:C | S ] , C , [ X:C | S ] ) :- X == V, !. % V is the same ref as X -- already in symbol table
map_var( V , [ X:Y | S ] , C , [ X:Y | Z ] ) :- X \== V, !, % V and X are different refs
fresh_symbol(V,S,C,Z). %
map_var( V , [] , C , [ X:C ] ). % not yet mapped var.