使用变量复制术语而不绑定变量

Copy term with variables without variables being bound

使用 SWI-Prolog。

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

我试过的

我试过了copy_term/2 and 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是predicate返回我需要的结果

?- 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

解决二进制表达式时需要这样做。原来是用来select谓词和求解表达式的。我称为本地的副本用于显示子表达式的重写,我称为全局的副本用于显示应用于整个表达式的重写。如果只有一个术语,例如没有副本,一旦变量被绑定一次使用,它会导致其他使用失败。

当前的解决方案是在谓词中为每次使用输入具有不同变量的多个术语。将其乘以数百甚至数千个可能存在输入错误或 copy/paste 错误的谓词,您就会发现这种需求。

其他注意事项

我也考虑过在谓词中有一个术语的主副本,然后用它来制作三个副本。问题是其中一个副本用于 selecting 谓词,因此在可以 selected 谓词之前,必须进行复制。因此,即使谓词未 select 用于评估,也必须在谓词中进行复制。

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 给我一份包含变量绑定的副本,这是谓词 selection 和评估部分所需的 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                   

(开头的一个非常小的评论:宁可使用单引号,而不是简单原子的双引号。)

第一种情况,相关部分为:

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 并且没有发现错误,请考虑使用 并在 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.