The facility presented here implements attributed variables in the
style of [9]. It provides a way for associating to
variables one or several arbitrary terms called attributes. By
allowing the user to redefine the unification of attributed variables,
this extension makes possible the design of coroutining facilities
(see subsection 9.2.7
)
and clean interfaces between Prolog and constraints solvers (see
section 10). This facility is available if the
attributes part of GNU Prolog has been installed.
A new type of data is introduced: attributed variables on which can
be attached one or several attributes. Currently, FD
variables cannot be attributed and unification between
attributed variables and FD variables always fails.
9.2.2 |
Attribute declaration - attribute/1 |
|
Templates
-
:- attribute(+structure_indicator)
Description
The directive attribute(Name/Arity) provides the means to
declare a new attribute which is a compound term of principal functor
Name/Arity. Attributes can be associated to a variable or updated
only if they have been previously declared using this directive.
Portability
GNU Prolog RH directives.
9.2.3 |
Attributes manipulation - get_atts/2,
put_atts/2 |
|
Templates
-
get_atts(-term, +callable_term)
Description
get_atts(Var, AccesSpec) gets the attributes of Var according
to AccessSpec or fails if Var is not an attributed variable.
Errors
|
AccesSpec is a generic variable |
|
instantiation_error |
|
AccesSpec is a compound term of principal functor
F/N but does not correspond to any attribute that has been
declared using the directive attributes/1 |
|
domain_error(attributes,F/N) |
|
Portability
GNU Prolog RH predicate.
Templates
-
put_atts(-term, +callable_term)
Description
put_atts(Var, AccesSpec) set the corresponding actual attribute of Var.
Errors
|
Var is a neither a variable nor an attributed variable |
|
type_error(variable,Var) |
|
AccesSpec is a generic variable |
|
instantiation_error |
|
AccesSpec is a compound term of principal
functor F/N but does not corresponding to any attribute that
has been declared using the directive attributes/1 |
|
domain_error(attributes,F/N) |
|
Portability
GNU Prolog RH predicate.
9.2.4 |
Type testing - attributed/1,
generic_var/1,
non_generic_var/1 |
|
Errors
None.
Portability
GNU Prolog predicate.
Templates
-
attributed(?term)
generic_var(?term)
non_generic_var(?term)
Description
attributed(Term) succeeds if Term is currently an
attributed variable, i.e. at least one attribute has been previously
attached to this variable using predicate put_atts/2.
Predicates generic_var/1 and non_generic_var/1
, defined in Type testing in the Finite Domain chapter
(section 8.4) are extended, as following : -
generic_var(Term) succeeds if Term is either a Prolog
variable, an FD variable or an attributed variable;
- non_generic_var(Term) succeeds if Term is neither a
Prolog variable nor an FD variable nor an attributed variable (opposite
of generic_var/1).
Errors
None.
Portability
GNU Prolog RH predicates.
9.2.5 |
Unification extension -
verify_attributes_predicate/1 |
|
The unification of attributed variables can be extended by defining
attributes verification handlers, that are user-defined
predicates checking that an attributed variable can be unified with
another one or with an non-variable term. An attributes
verification handler is declared by the following directive :
Templates
-
:- verify_attributes_predicate(+atom)
Description
The directive verify_attributes_predicate(Functor) declares
that the predicate Functor/3 is a attributes verification
handler. Using this directive the user can defined as many handlers as
(s)he wants, all of them being awaked in an unspecified order.
For example the directive verify_attributes_predicate(verify_foo) declares that verify_foo(Var, Value, Goal) must be called each time that the
unification algorithm tries to bind an attributed variable Var
to a non-variable term or to another attributed variable Value. If this call succeeds the unification resumes and Var is
actually bound to Value, otherwise the unification fails. Goal has to be unified by the handler to a goal which will be called
after the effective binding of Var.
Notes:- The handler should not try to bind Var. A binding of Var could be done after the end of the
complete unification using the parameter Goal.
- If Var is bound to another attributed variable, only the
attributes of Value are preserved. Therefore it could be
necessary to move attributes from Var to Value.
9.2.6 |
Attributed variables portraying -
portray_attributes_predicate/1 |
|
For printing attributed variables the Prolog top level uses
user-defined predicates that are called attributes portraying
handlers. To declare such handlers the user must use the following
directive:
Templates
-
:- portray_attributes_predicate(+atom)
Description
The directive portray_attributes_predicate(Functor) declares
that the predicate Functor/2 is an attribute portraying
handler. Using this directive the user can define as many handlers as
(s)he wants, all of them being called in an unspecified order.
Before printing the result of a query, the Prolog top level passes (as
first argument) the list of attributed variables of the answer to
every attribute portraying handler. It is expected that these
handlers always succeeds and unify their second argument to a
(possibly empty) list. Each elements of this list are then printed by
the the top level.
To illustrate the use of attributed variables, look at the following classical
program for of freeze/2. It is named myfreeze/2 to
avoid conflict with the built-in version of this predicate.
%%% File : myfreeze.pl %%%
%% declares a new attribute
:-attribute(myfrozen/1).
%% declares verify_myfreeze/3 as an attributes verification handler.
:-verify_attributes_predicate(verify_myfreeze).
verify_myfreeze(Var, Other, Goal):-
get_atts(Var, myfrozen(Fa)), !, % is Var revelant ?
( attributed(Other) -> % is Other attributed ?
( get_atts(Other, myfrozen(Fb)) -> % have a pending goal ?
put_atts(Other, myfrozen((Fa, Fb)))% makes conjunction of goals
; put_atts(Other, myfrozen(Fa)) % rescues the pending goal
), Goal=true % does nothing after unification
; Goal=Fa). % wakes the pending goal
verify_myfreeze(_, _, true). % succeeds if Var is not revelant
%% declares portray_myfreeze/2 as an attribute portraying handler.
:-portray_attributes_predicate(portray_myfreeze).
portray_myfreeze([H|T],L):-
(get_atts(H, myfrozen(G)) -> % is the head revelant ?
L = [myfreeze(H, G) | T2]; % produces output
L = T2), % throws the non-revelant vari
portray_myfreeze(T, T2). % treats the tail
portray_myfreeze([],[]).
myfreeze(X, Goal):-
put_atts(X, myfrozen(Goal)).
Now look the call of next goals :
-
| ?- [myfreeze].
compiling /usr/local/gprolog-1.2.16.rh/ExamplesATT/myfreeze.pl for byte code...
usr/local/gprolog-1.2.16.rh/ExamplesATT/myfreeze.pl compiled, 34 lines read -
4368 bytes written, 37 ms
yes
| ?- myfreeze(X,write('X'=X)), X=[].
X=[] % side effect
X = [] % bindings
yes
| ?- myfreeze(X,write('X'=X)).
myfreeze(X, write(X = X)) % attributes portray
yes
Copyright (C) 1999-2002 Daniel Diaz.
Chapters 9 and 10 : Copyright (C) 2002-2003 INRIA, Rémy Haemmerlé.
Verbatim copying and distribution of this entire article is permitted in any
medium, provided this notice is preserved.
More about the copyright