Attribute names are linked to modules. This means that certain
operations on attributed variables cause hooks to be called in
the module whose name matches the attribute name.
- A hook that must be defined in the module to which an attributed
variable refers. It is called after the attributed variable has
been unified with a non-var term, possibly another attributed variable.
AttValue is the attribute that was associated to the variable
in this module and VarValue is the new value of the variable.
If this predicate fails, the unification fails. If VarValue
is another attributed variable the hook often combines the two
attributes and associates the combined attribute with VarValue
- To be done
- The way in which this hook currently works makes the implementation of
important classes of constraint solvers impossible or at least extremely
impractical. For increased generality and convenience, simultaneous
unifications as in
[X,Y]=[0,1] should be processed
sequentially by the Prolog engine, or a more general hook should be
provided in the future. See Triska,
2016 for more information.
- This nonterminal is the main mechanism in which residual constraints are
obtained. It is called in every module where it is defined, and
Var has an attribute. Its argument is that variable. In each
module, attribute_goals//1 must describe a list of Prolog goals that are
declaratively equivalent to the goals that caused the attributes of that
module to be present and in their current state. It is always possible
to do this (since these attributes stem from such goals), and it is the
responsibility of constraint library authors to provide this mapping
without exposing any library internals. Ideally and typically, remaining
relevant attributes are mapped to pure and potentially
simplified Prolog goals that satisfy both of the following:
- They are declaratively equivalent to the constraints that were
- They use only predicates that are themselves exported and documented
in the modules they stem from.
The latter property ensures that users can reason about residual
goals, and see for themselves whether a constraint library behaves
correctly. It is this property that makes it possible to thoroughly test
constraint solvers by contrasting obtained residual goals with expected
This nonterminal is used by copy_term/3,
on which the Prolog top level relies to ensure the basic invariant of
pure Prolog programs: The answer is declaratively equivalent to
primitive uses attribute_goals//1 inside a findall/3
call. This implies that attribute_goals//1 can unify variables and
modify attributes, for example, to tell other hooks that some attribute
has already been taken care of. This nonterminal is also used by
which does not create a copy. Ideally attribute_goals//1 should
not modify anything to allow direct application in frozen/2.
In the current implementation frozen/2
backtracks over attribute_goals//1 to tolerate the current behavior.
This work-around harms the performance of frozen/2.
New implementations of attribute_goals//1 should avoid relying on
backtracking when feasible. Future versions of frozen/2
may require attribute_goals//1 not to modify any variables or
Note that instead of defaulty representations, a Prolog
list is used to represent residual goals. This simplifies
processing and reasoning about residual goals throughout all programs
that need this functionality.
- A hook that can be defined in each module to project constraints on
newly introduced variables back to the query variables.
QueryVars is the list of variables occurring in the query and
ResidualVars is a list of variables that have attributes
attached. There may be variables that occur in both lists. If possible, project_attributes/2
should change the attributes so that all constraints are expressed as
residual goals that refer only to
QueryVars, while other variables are existentially
- Called by write_term/2
and friends for each attribute if the option
attributes(portray) is in effect. If the hook succeeds the
attribute is considered printed. Otherwise
Module = ... is
printed to indicate the existence of a variable. This predicate is
deprecated because it cannot work with pure interface predicates like
Use attribute_goals//1 instead to map attributes to residual goals.