我正在尝试复制列表,以使原始列表不会因我在新列表上执行的任何操作而被更改。我看过prolog, copying lists和Prolog - copy a piece of list。但是,这两个选项都不会生成与其“父项”“独立”的列表。
来自必要的背景,一些Prolog概念很难掌握,我敢肯定我在这里缺少一些东西。所以我的问题是,是否可以在Prolog中创建列表的深层副本?
谢谢。
答案 0 :(得分:0)
列表只是一个穿着化装的术语。
[]
是一个简单的原子。[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]
,而不是 [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.