prologsicstus-prolog

Spurious attribute_goal/2 in SICStus Prolog 4.7.1


Given the following minimalistic "solver" in SICStus Prolog ...

:- module(attach, [attach/1]).
:- use_module(library(atts)).
:- attribute a/0.

attach(X) :- put_atts(X,a).

verify_attribute(_,_,[]).

attribute_goal(V,attach(V)) :- get_atts(V,a), put_atts(V,-a).

... I observe:

| ?- attach(X), copy_term(X,Xc,Xcc), copy_term(X,Yc,Ycc).
Xcc = attach:attach(Xc),
Ycc = true ? 

Where has the residual goal gone?!

Wasn't the put_atts/2 in attribute_goal/2 undone?


Edit. This previous answer (of a somewhat related question) hints at a similar issues when using the builtin predicate when/2.


Solution

  • No, the side effects (the put_atts(V, -a) that removes the attribute) of your attribute_goal/2 will not be undone by copy_term/3 (or frozen/2 et al.) and I do not think there is anything in the SICStus documentation that suggests that it would be.

    A simplified version of copy_term/3, that only handles variables, would look something like:

    my_copy_term(Var, Copy, Goal) :-
            (   attribute_goal(Var, VarGoal) ->
                true
            ;   VarGoal = true
            ),
            copy_term(Var-VarGoal, VarCopy-VarGoalCopy),
            Copy = VarCopy,
            Goal = VarGoalCopy.
    

    So, if attribute_goal/2 removes an attribute, like in your example, the attribute will still be absent when (my_)copy_term/3 succeeds.

    The effect of put_atts/2 will be undone on backtracking, as can be seen in the following two examples, where the first is your example, the second is the same but backtracking over the copy_term/3 before the second copy_term/3 is invoked.

    | ?- attach(X), copy_term(X,Xc,Xcc), copy_term(X,Yc,Ycc).
    Xcc = attach:attach(Xc),
    Ycc = true ? 
    yes
    % zip,source_info
    | ?- attach(X), (copy_term(X,Xc,Xcc); copy_term(X,Yc,Ycc)).
    Xcc = attach:attach(Xc) ? ;
    Ycc = attach:attach(Yc) ? ;
    no