This is a combination of getref/2 and setref/2, behaving like
swapref(Name, OldValue, NewValue) :-
getref(Name, OldValue),
setref(Name, NewValue).
Note that NewValue can be instantiated (or further instantiated)
_after_ the reference has been set to refer to it. Therefore it
is possible to use OldValue in the construction of NewValue.
% Example: a backtrackable counter
:- local reference(ctr, 0).
incref(Name) :-
swapref(Name, Old, New),
New is Old+1.
?- incref(ctr), incref(ctr), getref(ctr, C).
C = 2
Yes (0.00s cpu)
?- incref(ctr), incref(ctr), fail ; getref(ctr, C).
C = 0
Yes (0.00s cpu)
% Example: a backtrackable term stack
:- local reference(stack, []).
push(Name, X) :- swapref(Name, Xs, [X|Xs]).
pop(Name, X) :- swapref(Name, [X|Xs], Xs).
top(Name, X) :- getref(Name, [X|_]).
?- push(stack, a), push(stack, b), getref(stack, Xs).
Xs = [b, a]
Yes (0.00s cpu)
?- push(stack, a), push(stack, b), pop(stack, X), getref(stack, Xs).
X = b
Xs = [a]
Yes (0.00s cpu)
?- (push(stack, a) ; push(stack, b)), getref(stack, Xs).
Xs = [a]
Yes (0.00s cpu, solution 1, maybe more)
Xs = [b]
Yes (0.00s cpu, solution 2)