8.5 More on the CHR Language
The following subsections describe declarations, clauses, options and built-in
predicates of the CHR language.
Declarations name the constraint handler, its constraints, specify
their syntax and use in built-in labeling.
handler declaration documents the name of the constraint
handler. Currently it can be omitted, but will be useful in future releases for
constraints declaration lists the constraints
defined in the handler. A “SpecList” is a list of Name
pairs for the constraints.
The declaration of a constraint must appear before
the constraint handling rules and ECLiPSe clauses which define it,
otherwise a syntax error is raised.
There can be several constraints declarations.
operator declaration declares an operator, with
the same arguments as op/3 in ECLiPSe. However, while the usual
operator declarations are ignored during compilation from chr to
pl files, the CHR operator declarations are taken into account
(see also the subsection on clauses).
label_with declaration specifies when the
ECLiPSe clauses of a constraint can be used for built-in labeling
(see subsection on labeling).
Example, contd.: The first lines of the minmax handler are
constraints leq/2, neq/2, minimum/3, maximum/3.
operator(700, xfx, leq).
operator(700, xfx, neq).
8.5.2 ECLiPSe Clauses
A constraint handler program may also include arbitrary ECLiPSe code (written
with the four operators
:- /[1,2] and
Note that :-/1 and ?-/1 behave different from each other in CHR programs.
Clauses starting with :- are copied into the pl
file by the CHR compiler, clauses with ?- are executed
by the compiler. As the op declaration needs both copying and
execution, we have introduced the special operator declaration
(see previous subsection on declarations). A "Head" can be a "Constraint",
such clauses are used for built-in labeling only (see section on labeling).
The option command allows the user to set options in the CHR
Options can be switched on or off. Default is on.
Advanced users may switch an option off to improve the efficiency
of the handler at the cost of safety. Options are:
When executing a guard, it is checked that no global variables
(variables of the rule heads) are touched (see subsection on how
CHRs work). If the option is on, guards involving cut, if-then-else
or negation may not work correctly if a global variable has been touched before.
If switched off, guard checking may be significantly
faster, but only safe if the user makes sure that global variables are
not touched. To ensure that the variables are sufficiently bound,
tests like nonvar/1 or delays can be added to the predicates
used in the guards.
Before adding a user-defined constraint to the constraint store, it is
checked if there is an identical one already in the store. If there
is, the new constraint needs not to be added. The handling of the
duplicate constraint is avoided. This option can be set to
because the checking may be too expensive if duplicate constraints
rarely occur. Specific duplicate constraints can still be removed by
a simpagation rule of the form
Constraint \ Constraint <=> true.
In two-headed simplification rules, the intention is often to simplify
the two head constraints into a stronger version of one of the
constraints. However, a straightforward encoding of the rule may
include the case where the new constraint is identical to the
corresponding head constraint. Removing the head constraint and
adding it again in the body is inefficient and may cause termination
problems. If the
already_in_heads option is on, in such a case
the head constraint is kept and the body constraint ignored. Note
however, that this optimization currently only works if the body
constraint is the only goal of the body or the first goal in the
conjunction comprising the body of the rule (see the example handler
for domains). The option may be too expensive if identical head-body
constraints rarely occur.
- Note that the ECLiPSe environment flag
debug_compile (set and
nodbgcomp) is also taken into
account by the CHR compiler. The default is on.
If switched off, the resulting code is more
efficient, but cannot be debugged anymore (see section 8.8).
8.5.4 CHR Built-In Predicates
There are some built-in predicates to compile chr files, for
debugging, built-in labeling and to
inspect the constraint store and remove its constraints:
- chr2pl(File) compiles “File” from a chr to pl file.
- chr(File) compiles “File” from a chr to
pl file and loads the pl file.
chr_trace activates the standard debugger and
shows constraint handling.
chr_notrace stops either debugger.
provides built-in labeling (see corresponding subsection).
- chr_label_with(Constraint) checks if “Constraint” satisfies a
label_with declaration (used for built-in labeling).
- chr_resolve(Constraint) uses the ECLiPSe
clauses to solve a constraint (used for built-in labeling).
gets a constraint unifying with “Constraint” from the constraint
store and removes it, gets another constraint on backtracking.
- chr_get_constraint(Variable,Constraint) is the same as
chr_get_constraint/1 except that the constraint constrains the variable