使用没有变量绑定的变量复制术语

时间:2017-02-21 14:47:36

标签: prolog swi-prolog free-variable bound-variable

使用SWI-Prolog。

如何在没有绑定变量的情况下复制带变量的术语?

我尝试了什么

我尝试了copy_term/2duplicate_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.

我希望有一个内置的谓词。

TL; DR

对此的需求是解决二进制表达式。原始用于选择谓词并解决表达式。我称为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                   

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/2duplicate_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