Copy_term/2 is not relational and this is a problem

I’m currently trying to create an EBG using SWI-Prolog, however, copy_term/2 is not working properly as it should in the ISO Standard.

When i try to copy something like:

copy_term( (n_queens( GenQueens, GenSolution ), GenBody ), ( n_queens( [1, 2, 3, 4], Solution ), ( perm( [1, 2, 3, 4], P ), safe( P ))).

It succeeds but GenBody is not a copy of ( perm( [1, 2, 3, 4], P ), safe( P ) ) because GenBody is a variable and copy-term/2 is not relational.

How can i work around this?

Try switching sides, copy_term/2 has mode (+,-):

?- copy_term( ( n_queens( [1, 2, 3, 4], Solution ), 
                       ( perm( [1, 2, 3, 4], P ), safe( P ))),    
    (n_queens( GenQueens, GenSolution ), 
          GenBody )).
GenQueens = [1, 2, 3, 4],
GenBody = (perm([1, 2, 3, 4], _A), safe(_A)).

This is not a solution, because in EBG, GenBody’s perm list neither GenQueens should be instantiated. copy_term/2 should be relational. In EBG we always want to do copy_term((GenGoal :- GenBody), (Goal :- Body)), not the other way around.

Do you mean bi-directional? Thats impossible, copy_term/2 is defined as:

% The purpose of duplicate/2 is to get a new copy of 
% an expression with all new variables.
duplicate(Old, New) :- assert('$marker'(Old)), 
                       retract('$marker'(Copy)),
                       New = Copy.       % for steadfastness

It won’t touch Old unless New contains some variables of Old.

See also here:

https://www.cs.unm.edu/~luger/ai-final/code/PROLOG.ebg.html

You’re right, however, in the ISO Standard, copy_term/2 is relational, and in GNU Prolog it also is:

This important because we want it to copy both ways. SWI-Prolog implementation is most-likely wrong.

I’m truly very sorry, i was using clause(Goal, Body) instead of clause(GenGoal, GenBody) :man_facepalming: Sorry for wasting your time! Your implementation is correct :man_bowing: