Previous Up
9.2 Attributed variables

9.2.1 Introduction

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

9.2.7 A simple example

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
Previous Up