hProlog and SWI-Prolog style Attribute Declarations

The hProlog/SWI-Prolog is used in YAP to implement co-routining and several constraint solvers.

The following documentation is taken from the SWI-Prolog manual.

Binding an attributed variable schedules a goal to be executed at the first possible opportunity. In the current implementation the hooks are executed immediately after a successful unification of the clause-head or successful completion of a foreign language (built-in) predicate. Each attribute is associated to a module and the hook attr_unify_hook_50 "attr_unify_hook/2" is executed in this module. The example below realises a very simple and incomplete finite domain reasoner.

@icode :- module(domain, [ @ref domain_50 @"domain/2" % Var, ?Domain ]). :- use_module(library(ordsets)).

domain(X, Dom) :- var(Dom), !, get_attr(X, domain, Dom). domain(X, List) :- list_to_ord_set(List, Domain), put_attr(Y, domain, Domain), X = Y. @endicode

An attributed variable with attribute value Domain has been assigned the value Y.

@icode attr_unify_hook(Domain, Y) :- ( get_attr(Y, domain, Dom2) -> ord_intersection(Domain, Dom2, NewDomain), ( NewDomain == [] -> fail ; NewDomain = [Value] -> Y = Value ; put_attr(Y, domain, NewDomain) ) ; var(Y) -> put_attr( Y, domain, Domain ) ; ord_memberchk(Y, Domain) ). @endicode

Translate attributes from this module to residual goals: @icode attribute_goals(X) --> { get_attr(X, domain, List) }, [domain(X, List)]. @endicode

Before explaining the code we give some example queries:

The predicate @ref domain_50 @"domain/2" fetches (first clause) or assigns (second clause) the variable a domain, a set of values it can be unified with. In the second clause first associates the domain with a fresh variable and then unifies X to this variable to deal with the possibility that X already has a domain. The predicate @ref attr_unify_hook_50 @"attr_unify_hook/2" is a hook called after a variable with a domain is assigned a value. In the simple case where the variable is bound to a concrete value we simply check whether this value is in the domain. Otherwise we take the intersection of the domains and either fail if the intersection is empty (first example), simply assign the value if there is only one value in the intersection (second example) or assign the intersection as the new domain of the variable (third example). The nonterminal @ref attribute_goals_51 @"attribute_goals/3" is used to translate remaining attributes to user-readable goals that, when executed, reinstate these attributes.