使用SWI-Prolog。
如何在没有绑定变量的情况下复制带变量的术语?
我尝试了copy_term/2和duplicate_term/2
例如:
foo(c).
foo(E) :-
E = bar(a,b,X),
copy_term(E,Ec),
duplicate_term(E,Ed),
write("E: "),write(E),nl,
write("Ec: "),write(Ec),nl,
write("Ed: "),write(Ed),nl.
结果
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
E: bar(a,b,bar(a,b,bar(a,b,c)))
Ec: bar(a,b,bar(a,b,bar(a,b,c))) <-- Copy
Ed: bar(a,b,bar(a,b,bar(a,b,c))) <-- Duplicate
true.
?- foo(bar(a,b,bar(a,b,c))).
E: bar(a,b,bar(a,b,c))
Ec: bar(a,b,bar(a,b,c)) <-- Copy
Ed: bar(a,b,bar(a,b,c)) <-- Duplicate
true.
?- foo(bar(a,b,c)).
E: bar(a,b,c)
Ec: bar(a,b,c) <-- Copy
Ed: bar(a,b,c) <-- Duplicate
true.
并查看了Analyzing and Constructing Terms
部分这里En
是谓词返回我需要的结果
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
E: bar(a,b,bar(a,b,bar(a,b,c)))
En: bar(a,b,X), <-- Need this
true.
?- foo(bar(a,b,bar(a,b,c))).
E: bar(a,b,bar(a,b,c))
En: bar(a,b,X), <-- Need this
true.
?- foo(bar(a,b,c)).
E: bar(a,b,c)
En: bar(a,b,X), <-- Need this
true.
我希望有一个内置的谓词。
对此的需求是解决二进制表达式。原始用于选择谓词并解决表达式。我称为local的副本用于显示子表达式的重写,而我称为global的副本用于显示应用于整个表达式的重写。如果只有一个术语,例如没有副本,一旦变量绑定一次使用,就会导致其他用途失败。
当前的解决方案是使用不同的变量键入多个术语,以便每次使用到谓词中。将此数量乘以数百甚至数千个谓词,可能会输入或复制/粘贴错误,您可以看到需要。
我还考虑在谓词中使用该术语的主副本,然后使用它来制作三个副本。问题是其中一个副本用于选择谓词,因此在选择谓词之前,必须进行复制。因此,即使未选择谓词进行评估,也必须在谓词中进行复制。
foo(c).
foo(Ec) :-
M = bar(a,b,X),
copy_term(M,Ec),
duplicate_term(M,Ed),
write("M: "),write(M),nl,
write("Ec: "),write(Ec),nl,
write("Ed: "),write(Ed),nl.
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
M: bar(a,b,_9364)
Ec: bar(a,b,bar(a,b,bar(a,b,c)))
Ed: bar(a,b,_9384)
true.
?- foo(bar(a,b,bar(a,b,c))).
M: bar(a,b,_9240)
Ec: bar(a,b,bar(a,b,c))
Ed: bar(a,b,_9260)
true.
?- foo(bar(a,b,c)).
M: bar(a,b,_9116)
Ec: bar(a,b,c)
Ed: bar(a,b,_9136)
true.
因此
copy_term/2
为我提供了谓词选择和评估部分所需的变量绑定的副本
duplicate_term/2
给了我带有自由变量的术语,用于其他谓词。
Global Local
------------------ -----------------------------
Input (1 + ((0 + 0) + 0))
0 + X -> X (0 + 0) -> 0
= (1 + (0 + 0))
X + 0 -> X (0 + 0) -> 0
= (1 + 0)
X + 0 -> X (1 + 0) -> 1
= 1
答案 0 :(得分:3)
(开头的一个非常小的评论:使用单引号,而不是简单原子的双引号。)
在第一种情况下,相关部分是:
foo(E) :-
E = bar(a,b,X),
copy_term(E,Ec),
write('X' = X).
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
此处,E = bar(a,b,X)
已统一X
,以后无法撤消。使用$
- 调试器(见下文),我得到:
call:copy_term(bar(a,b,bar(a,b,bar(a,b,c))),A).
exit:copy_term(bar(a,b,bar(a,b,bar(a,b,c))),bar(a,b,bar(a,b,bar(a,b,c))))
因此简单地复制了基础术语。
在第二种情况下,相关部分是:
foo(Ec) :-
M = bar(a,b,X),
copy_term(M,Ec),
write('Ec: '),write(Ec),nl.
?- foo(bar(a,b,bar(a,b,bar(a,b,c)))).
首先注意变量! Ec
在一开始就是一个基础术语。这不会改变!无论你做什么。
你实际做的是将非基础术语复制到基础术语上。现在,字面意思是,您正在复制该术语,并且副本与基础术语统一。统一无法消除基础。
在这个片段中,你不满意复制的术语是基础的。实际上,在copy_term(M, Ec)
之前,术语Ec
已经基础。如果您使用了d-bugger并且未找到错误,请考虑使用simpler version,只需在$
前添加copy_term/2
即可。那就是:
foo(Ec) :-
M = bar(a,b,X),
$copy_term(M,Ec),
write('Ec: '),write(Ec),nl.
产生:
call:copy_term(bar(a,b,A),bar(a,b,bar(a,b,bar(a,b,c)))).
exit:copy_term(bar(a,b,A),bar(a,b,bar(a,b,bar(a,b,c)))).
Ec: bar(a,b,bar(a,b,bar(a,b,c)))
因此,copy_term/2
在这种情况下完全是多余的。
一些小的评论:
在SWI中,copy_term/2
和duplicate_term/2
之间的差异仅在您对条款进行破坏性更新时才具有相关性(不要!)。特别有问题的是两种复制约束都是以某种方式:
?- X #> Y, copy_term(X,C).
Y#=<X+ -1,
_3398#=<C+ -1,
_3398#=<C+ -1.
?- X #> Y, duplicate_term(X,C).
Y#=<X+ -1,
_3780#=<C+ -1.
?- X #> Y, copy_term_nat(X,C). % syntactic version
Y#=<X+ -1.
通常,维护约束的副本非常复杂,更好地避免或更普遍地对待它。 SICStus只提供纯语法copy_term/2
。如果您需要更多,则需要使用copy_term/3
。