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