Welcome to Constraint Handling Rules
ABSTRACT Constraint Handling Rules (CHR) is a declarative concurrent committed-choice constraint logic programming language consisting
of guarded rules that transform multisets of relations called constraints until no more change occurs. As an introduction
to CHR as a general-purpose programming language we present some small programs using different programming styles and discuss
Welcome to Constraint Handling Rules
Thom Fr¨ uhwirth
University of Ulm,
Abstract. Constraint Handling Rules (CHR) is a declarative concurrent
committed-choice constraint logic programming language consisting of
guarded rules that transform multisets of relations called constraints
until no more change occurs. As an introduction to CHR as a general-
purpose programming language we present some small programs using
different programming styles and discuss their properties.
Constraint Handling Rules (CHR) [Fr¨ u98, FA03, AFE05, SF05, Fr¨ u08] has not
only cut its niche as a special-purpose language for writing constraint solvers,
but also has been employed more and more as a general-purpose language in
computational logic, reasoning and beyond. This is because CHR can embed
many rule-based formalisms and implement algorithms in a declarative yet ef-
CHR was motivated by the inference rules that are traditionally used in com-
puter science to define logical relationships and arbitrary fixpoint computations.
Like automated theorem proving, CHR uses formulae to derive new information,
but only in a restricted syntax (e.g., no negation) and in a directional way (e.g.,
no contrapositives) that makes the difference between the art of proof search
and an efficient programming language.
CHR adapts concepts from term rewriting systems (TRS) [BN98] for pro-
gram analysis, for properties such as confluence [AFM99] and termination (e.g.
[Fr¨ u00]). Other influences for the design of CHR were the General Abstract
Model for Multiset Manipulation (GAMMA) [BCM88] and, of course, produc-
tion rule systems like OPS5 [BFKM85], but also integrity constraints and event-
condition-action rules found in relational databases and in deductive databases.
Implementations of CHR are abundant now. CHR does not necessarily impose
itself as a new programming language, but as a language extension that blends
in with the syntax of its host language, be it Prolog, Lisp, Haskell, C or Java.
In the host language, CHR constraints can be posted; in the CHR rules, host
language statements can be included.
The example programs here illustrate different programming styles in CHR.
This paper is based on some example programs of the author’s upcoming book
on CHR [Fr¨ u08].
T. Schrijvers and T. Fr¨ uhwirth (Eds.): Constraint Handling Rules, LNAI 5388, pp. 1–15, 2008.
c ? Springer-Verlag Berlin Heidelberg 2008
2T. Fr¨ uhwirth
A CHR program P is a finite set of rules consisting of constraints. (We do not
discuss declarations for CHR constraints here since they are implementation-
specific.) There are three kinds of rules:
Simplification rule: Name @ H ⇔ G B
[Name ’@’] H ’<=>’ [G ’|’] B.
Propagation rule:Name @ H ⇒ G B
[Name ’@’] H ’==>’ [G ’|’] B.
Simpagation rule: Name @ H1\H2⇔ G B
[Name ’@’] H1 ’\’ H2 ’==>’ [G ’|’] B.
Name is an optional, unique identifier of a rule, the (multi-)head (lhs, left hand
side) H (or H1 and H2) is a non-empty conjunction of CHR constraints, the
optional guard G is a conjunction of built-in constraints, and the body (rhs, right
hand side) B is a goal. A goal is a conjunction of built-in and CHR constraints.
If the guard is omitted from a rule, it means the same as “true ”.
Built-in constraints are predefined by the host language, while CHR con-
straints are defined by CHR rules.
Declaratively, a CHR rule logically relates head and body provided the guard
is true. A simplification rule means that the head is true if and only if the
body is true. A propagation rule means that the body is true if the head is
true. A simpagation rule Head1 \ Head2 <=> Body is logically equivalent to
the simplification rule Head1, Head2 <=> Head1, Body.
Basically, rules are applied to an initial conjunction of constraints (syntacti-
cally, a goal) until exhaustion (saturation), i.e. until no more change happens. An
initial goal is called query. The intermediate goals of a computation are stored
in the so-called (constraint) store. A final goal (store), to which no more rule is
applicable, is called answer (constraint) or result (of the computation).
We describe here (sequential) implementations according to the refined opera-
tional semantics [DSdlBH04] of CHR. Parallel or experimental implementations
may apply the rules in different ways, but of course still respect the standard
abstract operational semantics [Abd97].
A CHR constraint is both code and data. Every time a CHR constraint is
posted (added, called, executed, asserted, imposed) as part of a goal, it checks
itself the applicability of the rules it appears in. Such a constraint is called
(currently) active. One tries and applies rules in the order they are written in
the program, i.e. top-down and from left to right.
An active constraint is code which is evaluated like a procedure call. If, at
the moment, no rule is applicable that removes it, the active constraint becomes
passive data in the constraint store. It is called (currently) passive (delayed,
suspended, spleeping, waiting).
Passive constraints may be woken (reconsidered, resumed, re-executed) to
become active code if the environment (context) changes, concretely if their
arguments get more constrained. This is the case if a variable occurring in the
constraint gets more constrained by a built-in constraint.
Welcome to Constraint Handling Rules3
There are several computational phases when a CHR rule is tried (for ap-
plication) and finally applied (executed, triggered) (then it fires). These phases
correspond to the constituents of a rule, read from left to right:
Head Matching. For each rule, one of its head constraints is matched against the
active constraint. Matching succeeds if the constraint is an instance of the head,
i.e., the head serves as a pattern. If matching succeeded and the rule has more
than one head constraint, the constraint store is searched for partner constraints
that match the other head constraints. Head constraints are searched from left to
right, except that in simpagation rules, the constraints to be removed are tried
before the head constraints to be kept (this is done for efficiency reasons). If the
matching succeeds, the guard is checked. If there are several head constraints that
match the active constraint, the rule is tried for each such matching. Otherwise
the next rule is tried.
Guard Checking. A guard is a precondition on the applicability of a rule. The
guard is basically a test that either succeeds or fails. If the guard succeeds, the
rule applies, one commits to it and it fires. Otherwise the next rule is tried.
Body Execution. If the firing rule is a simplification rule, the matched constraints
are removed from the store and the body of the rule is executed by executing
the constraints in the body from left to right. Similarly for a firing simpagation
rule, except that the constraints that matched the head part preceding ’\’ are
kept. If the firing rule is a propagation rule the body of the rule is executed
without removing any constraints. It is remembered that the propagation rule
fired, so it will not fire again with the same constraints. When the currently
active constraint has not been removed, the next rule is tried. According to rule
type, we say that CHR constraints matching some constraint in the head of the
rule are either kept or removed constraints.
3 Multiset Transformation
The following simple algorithms are similar to the ones found in other rule-
based approaches, namely production rule systems and the GAMMA model of
computation, but in CHR the programs are more concise.
The General Abstract Model for Multiset Manipulation (GAMMA) framework
employs a chemical metaphor. States in a computation are chemical solutions
where floating molecules interact freely according to reaction rules. Reactions can
be performedin parallelprovidedtheyinvolvedisjointsetsof molecules.This isre-
ferred to as logical parallelism or declarative concurrency. We can model molecules
as CHR constraints.
These programs consist essentially of one constraint for representing active
data. Pairs of such constraints are rewritten by a single simplification rule. Often,
the rule can be written more compactly as a simpagation rule where one of the
constraints (the catalyst) is kept and the other is removed and possibly replaced
by an updated one. Optimizing CHR compilers will compile this to an efficient
in-place update instead of removing and adding constraints.
4T. Fr¨ uhwirth
We compute the minimum of a multiset of numbers ni, given as a computation
of the query min(n1), min(n2),..., min(nk). We interpret min(ni) to mean
that the number ni is potentially the minimum, that it is a candidate for the
min(N) \ min(M) <=> N=<M | true.
The simpagation rule takes two min candidates and removes the one with the
larger value. It keeps going until only one, the smallest value, remains as single
min constraint. The program illustrates the use of multi-headed rules instead of
explicit loops or recursion for iteration over data. This keeps the code extremely
compact and easy to analyse. The rule corresponds to the intuitive algorithm
that when we are to find the minimum from a given a list of numbers, we just
cross out larger numbers until one, the minimum, remains.
For example, this computation is possible (where constraints involved in a
rule application are underlined)
min(1), min(0), min(2), min(1)
min(0), min(2), min(1)
Program Properties. We used the rule application order of the refined semantics
of CHR implementations, where computation in a query proceeds from left to
right. In the abstract semantics, any order of rule applications is allowed, for
min(1), min(0), min(2), min(1)
min(1), min(0), min(1)
In the two examples above, the answer is the same. Actually, it is easy to
see that the answer will always be the same, i.e. the minimum value, no matter
in which order the rules are applied to which pair of constraints. We call this
The rules can even be applied in parallel to different parts of the query.
Obviously we arrive at the answer in less computation steps.
The program is obviously terminating, because the rule removes a CHR con-
straint and does not introduce new ones. Therefore the number of rule appli-
cations is one less than the number of min constraints. We can apply a rule in
constant time. Given any two min constraints, we can always apply the rule -
either in one pairing order or in the other. Therefore the complexity of this little
Welcome to Constraint Handling Rules5
program is linear in the number of min constraints, i.e. linear in the size of the
We can also stop the computation at any time and observe the current store
as intermediate answer. We can then continue by applying rules to this store
without the need to recompute from scratch and no need to remember anything
about how we arrived at the current store. If we stop again, we will observe
another intermediate answer that is closer to the final answer than the one
before. By closer we mean here that the store has less min constraints, i.e. less
candidates for the final minimum. The intermediate answers more and more
approximate the final answer. This property of a CHR program is called anytime
algorithm property. Note that by this description, an anytime algorithm is also
an approximation algorithm.
Now assume that while the program runs, we add a min constraint. It will
eventually participate in the computation in that the rule will be applied to it.
The answer will be correct, as if the newly added constraint had been there from
the beginning but ignored for some time. This property of a CHR program is
called incrementality or online algorithm property.
Guard Checking. So far we assumed that the min constraints contain given
values. In that case, the guard acts as a test that compares two such values. But
in general, under the abstract standard semantics, even though not necessarily
in a given CHR implementation, the guard is made out of built-in constraints
that hold if they are logically implied by the current store. While in current
practical implementations of CHR, a guard check will give an instantion error or
silently fail if unbound variables occur in it, the same guard check may succeed
under the abstract semantics. For example, the query min(A), min(B), A=<B
will reduce to min(A), A=<B, because we know that A=<B and that is exactly
what the guard asks for. Similarily, the query min(A), min(B), A<B will reduce
to min(A), A<B. Finally, the query min(A), min(A) will reduce to min(A). But
the query min(A), min(B) will not proceed, because we know nothing about
the relationship of the unknown values A and B.
Now consider what happens if we modify the program in that we strenghten
the guard. If we replace N=<M by N<M, multiple occurrences (duplicates) of the
final minimum constraint will no longer be removed. If we replace N=<M by N=M,
we will just remove duplicates. Both rules taken together have the same behavior
as our initial rule, provided we work with known values.
min(N) \ min(M) <=> N<M | true.
min(N) \ min(M) <=> N=M | true.
If values are only partially known, it turns out the the two rules are weaker
than the single initial rule. Consider the previous examples. Most of them still
work, but the query min(A), min(B), A=<B will not reduce at all, because the
built-in constraint A=<B is too weak to imply one of the guards of the two rules,
A<B or A=B. We say that these two programs are not operationally equivalent,
even though logically, they are. (The logical reading of rules as formulae is their
declarative semantics [Abd97].)