Attributes can be manipulated with the following three predicates (get_attr/3, put_attr/3 and del_attr/2) defined in the module machine.
One has to extend the default unification algorithm for used attributes by installing a handler in the following way:
:- install_verify_attribute_handler(
)
The
install_verify_attribute_handler/4
predicate is defined in module machine.
is the
attribute Module and
is a term with arguments
and
. The
term has to correspond to a
handler predicate that takes the value of the attribute (
)
and the term that the attributed value is bound to (
) as
arguments. To get good efficiency, it is usually best to keep the
handlers for each attribute module in separate XSB modules.
The handler is called after the unification of an attributed variable with a term or other attributed variable, if the attributed variable has an attribute in the corresponding module. The two arguments of the unification are already bound at the time the handler is called, i.e. the handler is a post-unify handler.
Here, by giving the implementation of a simple finite domain constraint solver (see the file fd.P below), we show how these lowlevel predicates for attributed variables can be used. In this example, an attribute in the module fd is used and the value of this attribute is a list of terms.
%% File: fd.P
%%
%% A simple finite domain constrait solver implemented using the lowlevel
%% attributes variables interface.
:- import put_attr/3, get_attr/3, del_attr/3,
install_verify_attribute_handler/4 from machine.
:- import member/2 from basics.
:- install_verify_attribute_handler(fd,AttrValue,Target,fd_handler(AttrValue,Target)).
fd_handler(Da, Target) :-
(var(Target), % Target is an attributed variable
get_attr(Target, fd, Db) -> % has a domain
intersection(Da, Db, [E|Es]), % intersection not empty
(Es = [] -> % exactly one element
Target = E % bind Var (and Value) to E
; put_attr(Target, fd, [E|Es]) % update Var's (and Value's)
)
; member(Target, Da) % is Target a member of Da?
).
intersection([], _, []).
intersection([H|T], L2, [H|L3]) :-
member(H, L2), !,
intersection(T, L2, L3).
intersection([_|T], L2, L3) :-
intersection(T, L2, L3).
domain(X, Dom) :-
var(Dom), !,
get_attr(X, fd, Dom).
domain(X, List) :-
List = [El|Els], % at least one element
(Els = [] % exactly one element
-> X = El % implied binding
; put_attr(Fresh, fd, List), % create a new attributed variable
X = Fresh % may call verify_attributes/2
).
show_domain(X) :- % print out the domain of X
var(X), % X must be a variable
get_attr(X, fd, D),
write('Domain of '), write(X),
write(' is '), writeln(D).