# Copy\_term but without maintaining variable relationships?

**URL:** <https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204>\
**Category:** Predicate\
**Created:** [July 26, 2021, 5:25pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204 "2021-07-26T17:25:00Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 26, 2021, 5:25pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/1 "2021-07-26T17:25:00Z")

</div>

Is there any predicate for making a copy of a compound term and un-unifying any unified variables, so that the resulting term has only singletons? In other words, is there something like a copy\_to\_singletons/2 that would let me do this:

```prolog
?- copy_to_singletons(foo(A, A), X).
X = foo(_1, _2).

```

I’ve been using this as a workaround, but it seems needlessly complex:

```prolog
copy_to_singletons(Term, TermOut) :-
    copy_term(Term, Term1, _),
    numbervars(Term1),
    mapsubterms([T0,_]>>var_number(T0, _), Term1, TermOut),

```

I end up having to make two copies because for whatever reason, mapsubterms/3 doesn’t call the goal for variables. Not sure what the reasoning is behind that, but it does mean I have to copy and ground before calling it.

Is there a better way?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 26, 2021, 10:23pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/2 "2021-07-26T22:23:24Z")

</div>

I’m curious why you want to do this. 😉

Anyway library(varnumbers) has varnumbers/3, which might do what you want instead of mapsubterms.

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 26, 2021, 11:22pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/3 "2021-07-26T23:22:13Z")

</div>

Unfortunately, varnumbers/3 is going to (by design) have the same problem as copy\_term, which is to say that common variables in the original will become common variables in the copy. As for what I’m trying to do, I want to reason about the structure of Prolog clauses themselves, so a non-singleton variable is _significant_ but that does not mean the two (or more) instances will be _identical_.

---

<div class="post-metadata">

**Author:** ![jan](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/jan/32/4_2.png) [@jan](https://swi-prolog.discourse.group/u/jan)\
**Post date:** [July 27, 2021, 7:14am UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/4 "2021-07-27T07:14:19Z")

</div>

> [@dmchurch](#):
>
> I want to reason about the structure of Prolog clauses themselves, so a non-singleton variable is _significant_ but that does not mean the two (or more) instances will be _identical_ .

I don’t understand that. I’ve seen a lot of things during my Prolog years, but never the desire to stop sharing two variables. As they are clause structures, they are not cyclic and thus a simple transformation as mapsubterms/3 does the job. You can’t use that as it doesn’t call the mapper for variables (it is still unclear whether that is a good decision. There are arguments both ways).

---

<div class="post-metadata">

**Author:** ![dmchurch](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/dmchurch/32/3427_2.png) [@dmchurch](https://swi-prolog.discourse.group/u/dmchurch)\
**Post date:** [July 27, 2021, 7:33am UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/5 "2021-07-27T07:33:10Z")

</div>

> [@jan](#):
>
> I’ve seen a lot of things during my Prolog years, but never the desire to stop sharing two variables.

Well, it’s always nice to be unique 😂 I want to map them into `term_position`s. I don’t want to use them semantically, I want to use them syntactically, and they are two different tokens in the stream.

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [July 27, 2021, 1:27pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/6 "2021-07-27T13:27:50Z")

</div>

Regardless of motivation this looks like a problem with a straight forward Prolog solution. Something like:

```prolog
copy_to_singletons(X, _) :- var(X), !.
copy_to_singletons(X, X) :- atomic(X), !.
copy_to_singletons([X|Xs], [S|Ss]) :- !,
	copy_to_singletons(X,S),
	copy_to_singletons(Xs,Ss).
copy_to_singletons(X, S) :- compound(X),
	X =.. [F|Xs],
	copy_to_singletons(Xs,Ss),
	S =.. [F|Ss].

```

so:

```prolog
?- copy_to_singletons(foo(A,A),X).
X = foo(_4786,_4792).

```

Am I missing something?

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 27, 2021, 3:33pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/8 "2021-07-27T15:33:51Z")

</div>

These lines aren’t needed (although they might speed things up):

> [@ridgeworks](#):
>
> ```prolog
> copy_to_singletons([X|Xs], [S|Ss]) :- !,
> copy_to_singletons(X,S),
> copy_to_singletons(Xs,Ss).
> 
> ```

because:

```prolog
?- [a|b] =.. F.
F = ['[|]', a, b].

```

and instead of (=…)/2, probably better to use compound\_name\_arguments/3.

Or mapargs/3 could be used:

```prolog
copy_to_singletons(X, _) :- var(X), !.
copy_to_singletons(X, X) :- atomic(X), !.
copy_to_singletons(X, S) :-
    mapargs(copy_to_singletons, X, S).

```

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [July 27, 2021, 4:01pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/9 "2021-07-27T16:01:05Z")

</div>

> [@peter.ludemann](#):
>
> These lines aren’t needed (although they might speed things up):

That was my first thought, but try it on the example.

> [@peter.ludemann](#):
>
> Or [mapargs/3](https://www.swi-prolog.org/pldoc/doc_for?object=mapargs/3) could be used:

Probably the best solution, but (like compound\_name\_arguments/3) not particularly portable.

---

<div class="post-metadata">

**Author:** ![peter.ludemann](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/peter.ludemann/32/48_2.png) [@peter.ludemann](https://swi-prolog.discourse.group/u/peter.ludemann)\
**Post date:** [July 27, 2021, 4:14pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/10 "2021-07-27T16:14:12Z")

</div>

> [@ridgeworks](#):
>
> try it on the example.

```prolog
?- copy_to_singletons(foo(A, A), X).
X = foo(_8998, _9000).

?- copy_to_singletons(foo(A,bar([A,zot(A)])), Z).
Z = foo(_7662, bar([_7696, zot(_7732)])).

```

---

<div class="post-metadata">

**Author:** ![ridgeworks](https://yyz2.discourse-cdn.com/free1/user_avatar/swi-prolog.discourse.group/ridgeworks/32/886_2.png) [@ridgeworks](https://swi-prolog.discourse.group/u/ridgeworks)\
**Post date:** [July 27, 2021, 4:48pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/11 "2021-07-27T16:48:48Z")

</div>

> [@peter.ludemann](#):
>
> ```prolog
> ?- copy_to_singletons(foo(A, A), X).
> X = foo(_8998, _9000).
> 
> ```

That’s odd because my version doesn’t terminate:

```prolog
?- copy_to_singletons(foo(A,A),X).
Action (h for help) ? goals
[1,572,043] copy_to_singletons([_7854, [[[[[[[...]]]]]]]], _31448902)
[1,572,042] copy_to_singletons([_7854, [[[[[[[...]]]]]]]], _31448882)
[1,572,041] copy_to_singletons([_7854, [[[[[[[...]]]]]]]], _31448862)
[1,572,040] copy_to_singletons([_7854, [[[[[[[...]]]]]]]], _31448842)
[1,572,039] copy_to_singletons([_7854, [[[[[[[...]]]]]]]], _31448822)
Action (h for help) ? abort
% Execution Aborted

```

This is because the argument list of the compound term `[A,A]` is `[A,[A]]`, i.e. indefinite.

```prolog
?- [A,A] =.. L.
L = ['[|]', A, [A]].

```

So there’s something going on here that I’m not understanding.

---

<div class="post-metadata">

**Author:** ![EricGT](https://avatars.discourse-cdn.com/v4/letter/e/f1d935/32.png) [@EricGT](https://swi-prolog.discourse.group/u/EricGT)\
**Post date:** [July 28, 2021, 1:53pm UTC](https://swi-prolog.discourse.group/t/copy-term-but-without-maintaining-variable-relationships/4204/12 "2021-07-28T13:53:11Z")

</div>

> [@ridgeworks](#):
>
> Am I missing something?

Bumped into [explain.pl](https://github.com/SWI-Prolog/swipl-devel/blob/9cf6502af6fbac5a078dd670f07e1b13905c1263/library/explain.pl) and thought of your question.

HTH
