1

使用 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.

并检查了分析和构建术语部分

我需要的

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;博士

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

当前的解决方案是在谓词中输入具有不同变量的多个术语以用于每次使用。将其乘以数百到可能数千个可能存在键入或复制/粘贴错误的谓词,您就会看到需要。

其他注意事项

我还考虑在谓词中拥有该术语的主副本,然后使用它来制作三个副本。问题是其中一个副本用于选择谓词,因此在选择谓词之前必须进行副本。因此,即使未选择谓词进行评估,也必须在谓词中发生副本。

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                   
4

1 回答 1

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,以后无法撤消。使用$-debugger(见下文)我得到:

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在这种情况下,完全是多余的。


copy_term/2一些小评论:在 SWI 中,和之间的区别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.

于 2017-02-21T18:31:56.337 回答