简体   繁体   中英

Copy term with variables without variables being bound

With SWI-Prolog.

How can a term with variables be copied without the variables being bound?

What I have tried

I tried copy_term/2 and duplicate_term/2

For example:

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.

results in

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

and checked the section Analyzing and Constructing Terms

What I need

Here En is the result of predicate returning what I need

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

I was hoping for a built-in predicate.

TL;DR

The need for this is in solving binary expressions. The original is used to select the predicate and to solve the expression. A copy I refer to as local is used to show the rewrite for the subexpression and a copy I refer to as global is used to show the rewrite applied to the entire expression. If there is only one term, eg no copies, once the variable is bound for one use, it causes the other uses to fail.

The current solution is to type in the multiple terms with different variables for each use into the predicate. Multiply this by hundreds to possibly thousands of predicates with possible typing or copy/paste mistakes and you can see the need.

Other considerations

I have also considered having a master copy of the term in the predicate and then using that to make the three copies. The problem with that is one of the copies is used in selecting the predicate, so before a predicate can be selected the copy would have to take place. So even if a predicate is not selected for evaluation a copy has to take place in the predicate.

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.

So
copy_term/2 gives me the copy with the variables bound which is needed for the predicate selection and evaluation part duplicate_term/2 gives me the term with the free variables for use with other predicates.

Example output from actual application

                    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                   

(A very tiny remark in the beginning: Rather use single quotes, not double quotes for simple atoms.)

In the first case, the relevant part is:

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)))).

Here, E = bar(a,b,X) already unifies X , which cannot be undone later on. With the $ -debugger (see below) I get:

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

So the ground term is simply copied.

In the second case, the relevant part is:

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)))).

First note the variables! Ec is in the beginning a ground term. And that will not change! No matter what you do.

What you actually do is to copy a non-ground term onto a ground term. Now, literally that means, you are copying the term, and the copy gets unified with the ground terms. Unification cannot undo the groundness.

In this fragment you are unhappy that the copied term is ground. In fact, prior to copy_term(M, Ec) , the term Ec is already ground. If you have used a d-bugger and have not found the error, consider a simpler version and simply add a $ in front of copy_term/2 . That is:

foo(Ec) :-
        M = bar(a,b,X),
        $copy_term(M,Ec),
        write('Ec: '),write(Ec),nl.

which produces:

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

So, the copy_term/2 is entirely redundant in this case.


Some minor remarks: In SWI, the difference between copy_term/2 and duplicate_term/2 is only of relevance when you do destructive update on terms (don't!). Particularly problematic is that both copy constraints somehow:

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

In general, maintaining copies of constraints is quite complex, better avoid it or treat it more generally. SICStus offers only a purely syntactic copy_term/2 . If you want more, you need to use copy_term/3 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM