as time goes by: constraint handling rules

49
Under consideration for publication in Theory and Practice of Logic Programming 1 As Time Goes By: Constraint Handling Rules A Survey of CHR Research from 1998 to 2007 JON SNEYERS, PETER VAN WEERT, TOM SCHRIJVERS, and LESLIE DE KONINCK Dept. of Computer Science, K.U.Leuven, Belgium (e-mail: FirstName.LastName @cs.kuleuven.be) submitted 1 January 2003; revised 1 January 2003; accepted 1 January 2003 Abstract Constraint Handling Rules (CHR) is a high-level programming language based on multi- headed multiset rewrite rules. Originally designed for writing user-defined constraint solvers, it is now recognized as an elegant general purpose language. CHR-related research has surged during the decade following the previous survey by Fr¨ uhwirth (1998). Covering more than 180 publications, this new survey provides an overview of recent results in a wide range of research areas, from semantics and anal- ysis to systems, extensions and applications. KEYWORDS: Constraint Handling Rules, CHR, survey Contents 1 Introduction 2 1.1 Historical Overview 2 1.2 Constraint Handling Rules 4 2 Semantics 6 2.1 Logical Semantics 7 2.2 Operational Semantics 8 3 Program Analysis 11 3.1 Confluence 11 3.2 Termination 12 3.3 Complexity 13 4 Systems and Implementation 14 4.1 Systems 14 4.2 Compilation 17 4.3 Programming Environments 21 5 Extensions and Variants 21 5.1 Deviating Operational Semantics 22 5.2 Language Extensions 23 5.3 Solver Hierarchies 25

Upload: others

Post on 03-Oct-2021

4 views

Category:

Documents


0 download

TRANSCRIPT

UntitledUnder consideration for publication in Theory and Practice of Logic Programming 1
As Time Goes By: Constraint Handling Rules
A Survey of CHR Research from 1998 to 2007
JON SNEYERS, PETER VAN WEERT,
TOM SCHRIJVERS, and LESLIE DE KONINCK
Dept. of Computer Science, K.U.Leuven, Belgium
(e-mail: [email protected])
submitted 1 January 2003; revised 1 January 2003; accepted 1 January 2003
Abstract
Constraint Handling Rules (CHR) is a high-level programming language based on multi- headed multiset rewrite rules. Originally designed for writing user-defined constraint solvers, it is now recognized as an elegant general purpose language.
CHR-related research has surged during the decade following the previous survey by Fruhwirth (1998). Covering more than 180 publications, this new survey provides an overview of recent results in a wide range of research areas, from semantics and anal- ysis to systems, extensions and applications.
KEYWORDS: Constraint Handling Rules, CHR, survey
Contents
2 Semantics 6
4.1 Systems 14
4.2 Compilation 17
5.2 Language Extensions 23
5.3 Solver Hierarchies 25
6.1 Set-Based Formalisms 25
6.2 Graph-Based Formalisms 26
7.3 Programming Language Development 31
7.4 Industrial CHR Users 34
8 Conclusions 35
8.2 Retrospection 36
References 40
1 Introduction
Constraint Handling Rules (CHR) is a high-level programming language based on
multi-headed, committed-choice, guarded multiset rewrite rules. Originally designed
in 1991 by Fruhwirth (1992; 1995; 1998; 2009) for the special purpose of adding
user-defined constraint solvers to a host-language, CHR has matured over the last
decade to a powerful and elegant general-purpose language with a wide spectrum
of application domains. Its logical semantics and monotonicity properties naturally
lead to anytime, online, and concurrent programs.
The previous survey on CHR (Fruhwirth 1998) was written in 1998. The aim of
this paper is to complement that survey by giving an overview of the last decade
of CHR-related research. We advise readers that are not yet familiar with CHR to
read Fruhwirth (1998) first as we have kept the amount of overlap minimal.
Overview. We start with a short historical overview of the past 10 years of CHR
research, followed by an introduction to the language itself. Section 2 describes the
logical and operational semantics; Section 3 covers program analysis topics such as
confluence, termination, and complexity. Next, in Section 4, we discuss the different
CHR systems and compilation techniques. Extensions and variants of CHR are dealt
with in Section 5, while Section 6 discusses the relation between CHR and other
formalisms. In Section 7 we give an overview of the many applications of CHR.
Finally, Section 8 concludes this survey.
1.1 Historical Overview
Early CHR research is performed at the Ludwig Maximilians Universitat (LMU)
and the European Computer-Industry Research Centre (ECRC), both in Munich,
by Fruhwirth (who later moves to Ulm) and his students Abdennadher (who later
moves to Cairo), Meuss, and Wolf (in Berlin).
At the end of the nineties, CHR research focusses on theoretical properties of
2
Fig. 1. CHR research groups all over the world: 1. Ulm, Germany (Fruhwirth, Meister, Betz,
Djelloul, Raiser, . . . ); 2. Leuven, Belgium (Schrijvers, Demoen, Sneyers, De Koninck, Van Weert,
. . . ); 3. Melbourne, Australia (Duck, Stuckey, Garca de la Banda, Wazny, Brand, . . . ); 4. Vi- enna, Austria (Holzbaur); 5. Berlin, Germany (Wolf); 6. Roskilde, Denmark (Christiansen); 7. Paris, France (Coquery, Fages); 8. Castellon, Spain (Escrig, . . . ); 9. Bologna/Ferrara, Italy (Mello, Lamma, Tacchella, . . . ); 10. Chieti, Italy (Meo, . . . ); 11. Cairo, Egypt (Abdennadher, . . . ); 12. Michigan, USA (Sarna-Starosta); 13. Vancouver, Canada (Dahl); 14. Recife, Brazil (Robin,
Vitorino, . . . ); 15. Singapore (Sulzmann, Lam);
CHR programs like confluence, completion, operational equivalence, termination,
and complexity (Section 3). In the same period, the seminal Holzbaur-Fruhwirth
CHR system in SICStus Prolog is developed (Holzbaur and Fruhwirth 1998; 1999;
2000a) and the first CHR systems in Java are created (Section 4.1.3).
Until about 2001, most of the CHR research is still done in Germany and Vi-
enna; other groups are discovering CHR, at first mostly as an implementation lan-
guage for applications. For instance, Sulzmann et al. use CHR for type systems
(Section 7.3.1) and Christiansen and Dahl develop CHR grammars for language
processing (Section 7.3.3). Meanwhile, Brand, Monfroy, Abdennadher and Rigotti
study the automatic generation of CHR programs (Section 7.1.5). Starting around
2002 there is a strong growth of international research interest in CHR, leading to a
series of workshops on CHR (Fruhwirth and Meister 2004; Schrijvers and Fruhwirth
2005b; Schrijvers and Fruhwirth 2006; Djelloul, Duck et al. 2007). Figure 1 gives an
(incomplete) overview of the most active CHR research groups all over the world.
In 2003 and 2004, the groups in Melbourne and Leuven start working on (static)
analysis and optimizing compilation of CHR, culminating in the Ph.D. theses of
Duck (2005) and Schrijvers (2005). This work leads to the formulation of the refined
operational semantics (Section 2.2.2) and the creation of new, highly optimizing
CHR systems (Section 4.2).
In Leuven and Brazil, research starts around 2005 on search and Java imple-
mentations of CHR (Sections 4.1.3 and 5.2.1), while the Ulm group investigates
alternative logical semantics for CHR (Section 2.1). The study of an implementa-
3
tion of the union-find algorithm in CHR leads to a focus on compiler optimizations
(Section 4.2.2) and the use of CHR for general-purpose programming (Section 7.2).
Recent trends in CHR-related research include the relation between CHR and
other formalisms (Section 6), extensions and variants of CHR (Section 5), and a
renewed interest in theoretical properties like confluence, termination, and complex-
ity (Section 3). In the context of the NICTA project “G12”, the Melbourne group
is currently developing Cadmium, an ACD term rewriting language which extends
CHR (Section 6). The Ulm group is currently researching global constraints in the
context of the DFG project “GLOBCON”; this work is related to automatic rule
generation (Section 7.1.5) and program transformation (Section 4.2.3).
1.2 Constraint Handling Rules
To make this survey somewhat self-contained, we briefly introduce the syntax and
informal semantics of Constraint Handling Rules. For a gentler introduction to
CHR, we refer the reader to Fruhwirth (1998), Fruhwirth and Abdennadher (2003),
Schrijvers (2005), Duck (2005), or Fruhwirth (2009).
CHR is embedded in a host language H that provides data types and a number
of predefined constraints. These constraints are called host language constraints
or built-in constraints. The traditional host language of CHR is Prolog. Its only
host language constraint is equality of Herbrand terms; its data types are Prolog
variables and terms. We denote the host language in which CHR is embedded
between round brackets: i.e. CHR(H) denotes CHR embedded in host language H.
Most systems are CHR(Prolog) systems, but there are also several implementations
of CHR(Java) and CHR(Haskell), and recently a CHR(C) system was developed.
A thorough discussion of existing CHR implementations is given in Section 4. We
require the host language to provide at least the basic constraints true and fail, and
syntactic equality (“==”) and inequality (“\==”) checks.
1.2.1 Syntax
CHR constraint symbols are drawn from the set of predicate symbols, denoted by a
functor/arity pair. CHR constraints, also called constraint atoms or constraints for
short, are atoms constructed from these symbols and the data types provided by
the host language. A CHR program P consists of a sequence of CHR rules. There
are three kinds of rules: (where l, m, n, o ≥ 1)
• Simplification rules: h1, . . . , hn ⇐⇒ g1, . . . , gm | b1, . . . , bo.
• Propagation rules: h1, . . . , hn =⇒ g1, . . . , gm | b1, . . . , bo.
• Simpagation rules: h1, . . . , hl \ hl+1, . . . , hn ⇐⇒ g1, . . . , gm | b1, . . . , bo.
The sequence, or conjunction, h1, . . . , hn are CHR constraints; together they are
called the head or head constraints of the rule. A rule with n head constraints is
called an n-headed rule and when n > 1, it is a multi-headed rule. All the head
constraints of a simplification rule and the head constraints hl+1, . . . , hn of a simp-
agation rule are called removed head constraints. The other head constraints — all
4
reflexivity @ leq(X,X) ⇐⇒ true. antisymmetry @ leq(X,Y), leq(Y,X) ⇐⇒ X = Y. idempotence @ leq(X,Y) \ leq(X,Y) ⇐⇒ true. transitivity @ leq(X,Y), leq(Y,Z) =⇒ leq(X,Z).
Fig. 2. The CHR(Prolog) program leq, a solver for the less-than-or-equal constraint.
heads of a propagation rule and h1, . . . , hl of a simpagation rule — are called kept
head constraints. The conjunction b1, . . . , bo consists of CHR constraints and host
language constraints; it is called the body of the rule. The part of the rule between
the arrow and the body is called the guard. It is a conjunction of host language
constraints. The guard “g1, . . . , gm | ” is optional; if omitted, it is considered to be
“true | ”. A rule is optionally preceded by name @ where name is a term. No two
rules may have the same name, and rules without an explicit name get a unique
name implicitly.
For simplicity, both simplification and propagation rules are often treated as
special cases of simpagation rules. The following notation is used:
Hk \ Hr ⇐⇒ G | B
If Hk is empty, then the rule is a simplification rule. If Hr is empty, then the rule
is a propagation rule. At least one of Hr and Hk must be non-empty.
1.2.2 Informal Semantics
A derivation starts from an initial query: a multiset of constraint atoms, given by
the user. This multiset of constraints is called the constraint store. The derivation
proceeds by applying the rules of the program, which modify the constraint store.
When no more rules can be applied, the derivation ends; the final constraint store
is called the solution or solved form.
Rules modify the constraint store in the following way. A simplification rule can be
considered as a rewrite rule which replaces the left-hand side (the head constraints)
with the right-hand side (the body constraints), on the condition that the guard
holds. The double arrow indicates that the head is logically equivalent to the body,
which justifies the replacement. The intention is that the body is a simpler, or more
canonical form of the head.
In propagation rules, the body is a consequence of the head: given the head,
the body may be added (if the guard holds). Logically, the body is implied by
the head so it is redundant. However, adding redundant constraints may allow
simplifications later on. Simpagation rules are a hybrid between simplification rules
and propagation rules: the constraints before the backslash are kept, while the
constraints after the backslash are removed.
1.2.3 Examples
The program leq (Fig. 2) is a classic example CHR program to solve less-than-or-
equal constraints. The first rule, reflexivity, replaces the trivial constraint leq(X,X)
5
generate @ upto(N) ⇐⇒ N > 1 | prime(N), upto(N-1). done @ upto(1) ⇐⇒ true. remove nonprime @ prime(A) \ prime(B) ⇐⇒ B mod A = 0 | true.
Fig. 3. The CHR program primes, a prime number sieve.
by true. Operationally, this entails removing this constraint from the constraint
store (the multiset of all known CHR constraints). The second rule, antisymmetry,
states that leq(X,Y) and leq(Y,X) are logically equivalent to X = Y. Operationally
this means that constraints matching the left-hand side may be removed from the
store, after which the Prolog built-in equality constraint solver is used to unify X
and Y. The third rule, idempotence, removes redundant copies of the same leq/2
constraint. It is necessary to do this explicitly since CHR has multiset semantics.
The last rule, transitivity, is a propagation rule that computes the transitive closure
of the leq/2 relation. An example derivation could be as follows:
leq(A,B), leq(B,C), leq(C,A)
(transitivity) leq(A,B), leq(B,C), leq(C,A), leq(B,A)
(antisymmetry) leq(B,C), leq(C,A), A = B
(Prolog) leq(A,C), leq(C,A), A = B
(antisymmetry) A = C, A = B
Figure 3 lists another simple CHR(Prolog) program called primes, a CHR variant
of the Sieve of Eratosthenes. Dating back to at least 1992 (Fruhwirth 1992), this is
one of the very first examples where CHR is used as a general-purpose programming
language. Given a query of the form “upto(n)”, where n is a positive integer, it
computes all prime numbers up to n. The first rule (generate) does the following: if
n > 1, it ‘simplifies’ upto(n) to upto(n− 1) and adds a prime(n) constraint. The
second rule handles the case for n = 1, removing the upto(1) constraint. Note that
removing a constraint is done by simplifying it to the built-in constraint true. The
third and most interesting rule (remove nonprime) is a simpagation rule. If there
are two prime/1 constraints prime(A) and prime(B), such that B is a multiple
of A, the latter constraint is removed. The effect of the remove nonprime rule is to
remove non-primes. As a result, if the rules are applied exhaustively, the remaining
constraints correspond exactly to the prime numbers up to n.
2 Semantics
In this section, we give an overview of both the logical (declarative) semantics and
the operational semantics of CHR. The logical semantics (Section 2.1) constitute
the formal foundations for the CHR programming language, whilst the operational
semantics (Section 2.2) determine the behavior of actual implementations.
6
2.1.1 Classical Logic Semantics
Let x denote the variables occurring only in the body of the rule. We use ∀(F )
to denote universal quantification over all free variables in F . A simplification rule
H ⇐⇒ G | B corresponds to a logical equivalence, under the condition that
the guard is satisfied: ∀(G → (H ↔ ∃xB)). A propagation rule H =⇒ G | B
corresponds to a logical implication if the guard is satisfied: ∀(G → (H → ∃xB)).
A simpagation rule Hk \ Hr ⇐⇒ G | B corresponds to a conditional equivalence:
∀(G → (Hk → (Hr ↔ ∃xB))). The (classical) logical semantics (Fruhwirth 1998) of
a CHR program — also called its logical reading, declarative semantics, or declar-
ative interpretation — is given by the built-in constraint theory DH (which defines
the built-ins of the host language H) in conjunction with the logical formulas for
each rule. As an example, consider the program leq of Fig. 2. The logical formulas
corresponding to its rules are the following:







∀x, y : x = y → (leq(x, y) ↔ true) (reflexivity)
∀x, y, x′, y′ : x = x′ ∧ y = y′ → (leq(x, y) ∧ leq(y′, x′) ↔ x = y) (antisymmetry)
∀x, y, x′, y′ : x = x′ ∧ y = y′ → (leq(x, y) → (leq(x′, y′) ↔ true)) (idempotence)
∀x, y, y′, z : y = y′ → (leq(x, y) ∧ leq(y′, z) → leq(x, z)) (transitivity)
or equivalently:
true (idempotence)
∀x, y, z : leq(x, y) ∧ leq(y, z) → leq(x, z) (transitivity)
Note the strong correspondence between the syntax of the CHR rules, their logical
reading, and the natural definition of partial order.
The classical logical reading, however, does not reflect CHR’s multiset semantics
(the idempotence rule is logically equivalent to true). Also, the classical logic reading
does not always make sense. For example, consider the classical logic reading of the
primes program of Fig. 3:



∀n : n > 1 → upto(n) ↔ ∃n′prime(n) ∧ n′ = n − 1 ∧ upto(n′) (generate)
upto(1) ↔ true (done)
which is equivalent to:
upto(1) (done)
∀a, b : prime(a) ∧ a|b → prime(b) (remove nonprime)
The last formula nonsensically states that a number is prime if it has a prime factor.
7
2.1.2 Linear Logic Semantics
For general-purpose CHR programs such as primes, or programs that rely on CHR’s
multiset semantics, the classical logic reading is often inconsistent with the intended
meaning (see previous section). To overcome these limitations, Bouissou (2004) and
Betz and Fruhwirth (2005; 2007) independently proposed an alternative declara-
tive semantics based on (intuitionistic) linear logic. The latter, most comprehensive
study provides strong soundness and completeness results, as well as a semantics
for the CHR∨ extension of CHR (see Section 5.2.1). For CHR programs whose
constraints represent a multiset of resources, or whose rules represent unidirec-
tional actions or updates, a linear logic semantics proves much more appropriate.
A simple example is the following coin-throwing simulator (which depends on the
nondeterminism in the operational semantics):
throw(Coin) ⇐⇒ Coin = head.
throw(Coin) ⇐⇒ Coin = tail.
The classical logic reading of this program entails head = tail. The linear logic
reading of the coin-throwing program boils down to the following formula:
!(throw(Coin) (Coin = head)&(Coin = tail))
In natural language, this formula means “you can always replace throw(Coin) with
either (Coin = head) or (Coin = tail), but not both”. This corresponds to the
committed-choice and unidirectional rule application of CHR.
2.1.3 Transaction Logic Semantics
The linear logic semantics is already closer to the operational semantics than the
CHR classical logical semantics. However, it still does not allow precise reasoning
about CHR derivations: while derivations correspond to proofs of logic equivalence
of the initial and the final state, it only allows reasoning on the result of an execu-
tion, not on the execution itself. The transaction logic semantics (Meister, Djelloul
et al. 2007) bridges the remaining gap between the logical and operational semantics
of CHR by providing a framework for both inside one formal system.
2.2 Operational Semantics
The behavior of CHR implementations is determined by their operational seman-
tics. As the original theoretical semantics of CHR (Section 2.2.1) proved too non-
deterministic for practical programming, more deterministic instances have been
specified that offer more execution control (Sections 2.2.2 and 2.2.3).
2.2.1 Theoretical Operational Semantics ωt
The operational semantics ωt of CHR (Fruhwirth 1998), sometimes also called the-
oretical or high-level operational semantics, is highly nondeterministic. It is formu-
lated as a state transition system.
8
Definition 2.1
An identified CHR constraint c#i is a CHR constraint c associated with some
unique integer i, the constraint identifier. This number serves to differentiate be-
tween copies of the same constraint. We introduce the functions chr(c#i) = c and
id(c#i) = i, and extend them to sequences and sets of identified CHR constraints
in the obvious manner, e.g., id(S) = {i|c#i ∈ S}.
Definition 2.2
An execution state σ is a tuple G, S, B, Tn. The goal G is a multiset of constraints
to be rewritten to solved form. The CHR constraint store S is a set of identified
CHR constraints that can be matched with rules in the programP . Note that chr (S)
is a multiset although S is a set. The built-in constraint store B is the conjunction
of all built-in constraints that have been posted to the underlying solver. These
constraints are assumed to be solved (implicitly) by the host language H. The
propagation history T is a set of tuples, each recording the identities of the CHR
constraints that fired a rule, and the name of the rule itself. The propagation history
is used to prevent trivial non-termination for propagation rules: a propagation rule
is allowed to fire on a set of constraints only if the constraints have not been used to
fire the same rule before.1 Finally, the counter n ∈ N represents the next integer that
can be used to number a CHR constraint. We use σ, σ0, σ1, . . . to denote execution
states and Σchr to denote the set of all execution states.
For a given CHR program P , the transitions are defined by the binary rela-
tion P⊂ Σchr × Σchr shown in Figure 4. Execution proceeds by exhaustively
applying the transition rules, starting from an initial state.
The Solve transition solves a built-in constraint from the goal, the Introduce
transition inserts a new CHR constraint from the goal into the CHR constraint
store, and the Apply transition fires a rule instance. A rule instance instantiates
a rule with CHR constraints matching the heads, using a matching substitution (a
one-way variable substitution).
Relatively strong soundness and completeness results (Fruhwirth 1998) link the
logical semantics and the operational semantics. Maher (2002) discusses the notion
of propagation completeness and proves an impossibility result for CHR.
Variants of ωt have been introduced to formalize extensions and variants of CHR.
For example, the operational semantics of CHR∨(Abdennadher 2000), probabilistic
CHR (Fruhwirth, Di Pierro et al. 2002), and CHR with aggregates (Sneyers, Van
Weert et al. 2007) are all based on ωt. We discuss these and other extensions in
Section 5.
1 Early work on CHR, as well as some more recent publications (e.g., Bouissou 2004; Duck, Stuckey et al. 2007; Haemmerle and Fages 2007), use a token store instead of a propagation history (this explains the convention of denoting the propagation history with T). A token store contains a token for every potential (future) propagation rule application, which is removed when the rule is actually applied. The propagation history formulation is dual, but closer to most implementations. Confusingly, the term token store has also been used for what is commonly referred to as the “propagation history” (e.g., Chin, Sulzmann et al. 2003; Tacchella, Gabbrielli et al. 2007).
9
1. Solve. {c} G, S,B, Tn P G, S, c ∧ B, Tn where c is a built-in constraint and DH |= ∃∅B.
2. Introduce. {c} G, S,B, Tn P G, {c#n} ∪ S, B, Tn+1
where c is a CHR constraint and DH |= ∃∅B. 3. Apply. G, H1 H2 S, B, Tn P B G, H1 S, θ ∧ B, T ∪ {h}n
where P contains a (renamed apart) rule of the form r @ H ′ 1 \ H ′
2 ⇐⇒ G | B, θ is a matching substitution such that chr(H1) = θ(H ′
1) and chr(H2) = θ(H ′ 2),
h = (r, id(H1), id(H2)) 6∈ T, and DH |= (∃∅B) ∧ (B → ∃B(θ ∧ G)).
Fig. 4. The transition rules of the theoretical operational semantics ωt, defining P . We use for multiset union. For constraint conjunctions B1 and B2, ∃B2
(B1) denotes ∃X1, . . . , Xn : B1, with {X1, . . . , Xn} = vars(B1)\vars(B2).
We should also mention the work on an and-compositional semantics for CHR
(Delzanno, Gabbrielli et al. 2005; Gabbrielli and Meo 2009), which allows one to
retrieve the semantics of a conjunctive query given the semantics of the conjuncts.
This property is a first step towards incremental and modular analysis and verifi-
cation tools.
2.2.2 Refined Operational Semantics ωr
The refined operational semantics ωr (Duck, Stuckey et al. 2004) instantiates the
ωt operational semantics by removing much of the nondeterminism. It formally
captures the behavior of many CHR implementations (see also Section 4). CHR
programs often rely on the execution control offered by the ωr semantics for cor-
rectness, or to achieve a good time complexity.
The refined operational semantics uses a stack of constraints: when a new con-
straint arrives in the constraint store it is pushed on the stack. The constraint
on top of the stack is called the active constraint. The active constraint attempts
to match rule heads, together with suitable constraints from the constraint store
(partner constraints), All occurrences of the active constraint are tried in the order
in which they occur in the program. When all occurrences have been tried, the
constraint is popped from the stack. When a rule fires, its body is executed im-
mediately from left to right, thereby potentially suspending the active constraint
because of newly arriving constraints. When a constraint becomes topmost again,
it resumes its search for matching clauses.
Alternative formalizations of the ωr semantics have been made for easier reason-
ing about certain optimizations or analyses. Examples are the call-based refined
operational semantics ωc (Schrijvers, Stuckey et al. 2005) and the semantics for
occurrence representations ωo (Sneyers, Schrijvers et al. 2005). Variants of ωr have
also been introduced to formalize implementations of proposed extensions to CHR
or variants of CHR. To mention just a few of them: the ω¬r semantics for CHR¬ (Van
Weert, Sneyers et al. 2006), the ω∨ r semantics for CHR∨ which is equivalent to the
tree-based ω semantics (De Koninck, Schrijvers et al. 2006b), the set-based ωset semantics of CHRd (Sarna-Starosta and Ramakrishnan 2007), and the concurrent
refined semantics (Lam and Sulzmann 2007). These extensions and variants are
discussed in more detail in Section 5.
10
2.2.3 Priority Semantics ωp
While the refined operational semantics reduces most of the nondeterminism of
the ωt semantics, it arguably does not offer the CHR programmer an intuitive and
predictable way to influence control flow. The ωr semantics in a sense forces the
programmer to understand and take into account how CHR implementations work,
to achieve the desired execution control. De Koninck, Schrijvers et al. (2007b) in-
troduced the extension CHRrp, with a corresponding operational semantics called
ωp. The programmer assigns a priority to every rule. The ωp semantics is an in-
stantiation of ωt which ensures that of all applicable rules, the one with the highest
priority is applied first. This feature gives the programmer a much more precise
and high-level control over program execution compared to the ωr semantics.
3 Program Analysis
In this section we discuss important properties of CHR programs: confluence (Sec-
tion 3.1), termination (Section 3.2), and complexity (Section 3.3), as well as (semi-)
automatic analysis of these properties. Program analyses that are mostly used for
optimizing compilation are discussed in Section 4.2.2.
3.1 Confluence
If for a given CHR program, for all initial states, any ωt derivation from that
state results in the same final state, the program is called confluent. Confluence
has been investigated thoroughly in the context of CHR (Abdennadher, Fruhwirth
et al. 1999). Two important results are discussed already in (Fruhwirth 1998): the
existence of a decidable, sufficient and necessary test for confluence of terminating
programs, and the result that confluence implies correctness (consistency of the log-
ical reading). Confluence under the refined ωr semantics is investigated in Chapter
6 of (Duck 2005), which also discusses a refined confluence test.
Recently, the topic of confluence received renewed attention because certain prob-
lems and limitations of the confluence test have surfaced. Firstly, many programs
that are in practice confluent fail this confluence test because non-confluence orig-
inates from unreachable states. The more powerful notion of observable confluence
(Duck, Stuckey et al. 2007) takes reachability into account. Secondly, the stan-
dard notion of confluence is only applicable to terminating programs. Raiser and
Tacchella (2007) extended the notion of confluence to non-terminating programs.
Haemmerle and Fages (2007) develop a notion of abstract critical pairs for rewrit-
ing systems in general. They illustrate this notion for CHR’s theoretical semantics.
A particularly interesting result is that some traditional critical pairs can be disre-
garded because they are redundant.
Related Analyses. Abdennadher and Fruhwirth (1998) showed how to do comple-
tion of CHR programs. Completion is a technique to transform a non-confluent
program into a confluent one by adding rules. It allows extension, modification and
specialization of existing programs.
11
A very useful notion is that of operational equivalence of two CHR programs.
Two programs are operationally equivalent if for each query, the answer is the
same (modulo variable renaming) according to each program. A straightforward
extension of confluence, called compatibility of two programs, is shown to be too
weak to capture the operational equivalence of CHR programs (Abdennadher and
Fruhwirth 1999; Abdennadher 2001). Instead, Abdennadher and Fruhwirth (1999)
give a decidable, sufficient, and necessary syntactic condition for operational equiv-
alence of well-behaved (confluent and terminating) CHR programs. A sufficient syn-
tactic condition is also given for the equivalence of two CHR constraints, defined
in two different well-behaved CHR programs. The latter condition is also shown
necessary for an interesting class of CHR programs.
Abdennadher and Fruhwirth (2004) investigated the merging of two well-behaved
CHR solvers. If the two programs are not compatible, well-behavedness can be
regained by completion. Furthermore, Abdennadher and Fruhwirth (2004) identify
a class of solvers whose union is always confluent, and argue why finding a class
whose union preserves termination is hard. Finally, Abdennadher and Fruhwirth
(2004) present a method to remove redundant rules from CHR programs, based on
the notion of operational equivalence.
3.2 Termination
The first work on termination analysis of CHR programs was presented by Fruhwirth
(2000). Fruhwirth demonstrated that termination proof techniques from logic pro-
gramming and term rewrite systems can be adapted to the CHR context. Termina-
tion of CHR programs is proved by defining a ranking function from computation
states to a well-founded domain such that the rank of consecutive computation
states decreases. A condition on simplification rules guarantees such rank decreases
for all consecutive states. This approach, however, cannot prove termination of
CHR programs with propagation rules, because it is impossible to show decreases
between consecutive states as these rules do not remove constraints from the store.
Recently, two new results on termination analysis of CHR were presented. Pilozzi,
Schrijvers et al. (2007) describe a termination preserving transformation of CHR
programs to Prolog programs. By reusing termination tools from logic programming
and, indirectly, from term rewriting, proofs of termination of the transformed CHR
programs are generated automatically, yielding the first fully automatic termination
prover for CHR. The transformation, however, does not consider propagation his-
tories. As such, it is applicable only to CHR programs without propagation rules. A
transformation of single-headed propagation rules to equivalent simplification rules
overcomes this problem partially.
The second contribution is presented by Voets, Pilozzi et al. (2007). Compare to
previous approaches, theirsapproach is applicable to a much larger class of CHR pro-
grams. By formulating a new termination condition that verifies conditions imposed
on the dynamic process of adding constraints to the store, they derive conditions
for both simplification and propagation rules.
12
3.3 Complexity
For various CHR programs — general purpose programs as well as constraint solvers
— an accurate, though rather ad hoc, complexity analysis has been made. We
list the most notable examples in Section 3.3.1. While ad hoc methods give the
most accurate results in practice, they cannot easily be generalized. Therefore,
more structured approaches to complexity analysis have been proposed by means
of meta-complexity theorems. An overview is given in Section 3.3.2.
3.3.1 Ad Hoc Analysis
A CHR implementation of the classical union-find algorithm was proven optimal
by Schrijvers and Fruhwirth (2006). Sneyers, Schrijvers et al. (2006a) showed the
optimal complexity of an implementation of Dijkstra’s shortest path algorithm that
uses Fibonacci heaps. Fruhwirth (2005a) formulated the complexity of a general-
purpose lexicographical order constraint solver in terms of the number of ask and tell
built-in constraints encountered during execution. Finally, Meister, Djelloul et al.
(2006) derived the complexity of a solver for existentially quantified equations over
finite and infinite trees, using bounds on the derivation length.
3.3.2 Meta-Complexity Results
Fruhwirth (2001; 2002a; 2002b) investigated the time complexity of simplification
rules for naive implementations of CHR. In this approach, a suitable termination
order (called a tight ranking) is used as an upper bound on the derivation length.
Combined with a worst-case estimate of the number and cost of rule application
attempts, this results in a complexity meta-theorem which gives a rough upper
bound of the time complexity. Recent work on optimizing compilation of CHR (cf.
Section 4.2.2) allows meta-theorems that give much tighter complexity bounds. We
now discuss two distinct approaches.
Ganzinger and McAllester (2002) propose a formalism called Logical Algorithms
(LA) and prove a meta-complexity result. De Koninck, Schrijvers et al. (2007a)
establish a close correspondence between CHR and LA (see also Section 6.1.3),
allowing the LA meta-complexity result to be applied (indirectly) to a large class
of CHR programs. De Koninck, Schrijvers et al. (2007a) actually address the meta-
complexity of CHRrp programs, an extension of CHR discussed in Section 5.1.3.
All CHR programs are also CHRrp programs. The Logical Algorithms approach
was previously used, in a more ad hoc way, by Christiansen (2005) to derive the
complexity of CHR grammars (see Section 7.3.3).
Sneyers, Schrijvers et al. (2009) explicitly decouple the two steps in the approach
of Fruhwirth (2002a; 2002b) by introducing abstract CHR machines. In the first
step, the number of rule applications is estimated; this corresponds to the number of
CHR machine steps. If a suitable termination order can be found, it can be used to
show an upper bound. However for programs that are non-terminating in general,
like a RAM machine simulator, or for which no suitable ranking can be found,
other techniques have to be used to prove complexity properties. In the second
13
step, the complexity of rule application is computed for a given CHR program;
this corresponds to simulating a CHR machine on a RAM machine. The first step
depends only on the operational semantics of CHR, whereas the second step depends
strongly on the performance of the code generated by the CHR compiler.
3.3.3 Complexity-wise Completeness of CHR
Sneyers, Schrijvers et al. (2009) also consider the space complexity of CHR pro-
grams. Some compiler optimizations like memory reuse (Sneyers, Schrijvers et al.
2006b) are crucial to achieve tight space complexity bounds (cf. Section 4.2.2).
The most interesting result of Sneyers, Schrijvers et al. (2009) is the following
“complexity-wise completeness” result for CHR, which implies that “everything
can be done efficiently in CHR”: For every algorithm (RAM machine program)
which uses at least as much time as space, a CHR program exists which can be
executed in the K.U.Leuven CHR system with time and space complexity within
a constant from the original complexities. Complexity-wise completeness implies
Turing completeness but is a much stronger property.
4 Systems and Implementation
CHR is first and foremost a programming language. Hence, a large part of CHR
research has been devoted to the development of CHR systems and efficient execu-
tion of CHR programs. The two most comprehensive works on this subject are the
Ph.D. theses of Duck (2005) and Schrijvers (2005). In this section, we provide an
overview of their work as well as the many other contributions to the field.
4.1 Systems
Since the conception of CHR a large number of CHR systems (compilers, inter-
preters and ports) have been developed. In particular, in the last ten years the
number of systems has exploded. Figure 5 presents a timeline of system develop-
ment, branches and influences. We discuss these systems, grouped by host language
or host paradigm, in more detail.
4.1.1 CHR(LP)
Logic Programming is the natural host language paradigm for CHR. Hence, it is
not surprising that the CHR(Prolog) implementations are the most established
ones. Holzbaur and Fruhwirth (2000a) have laid the groundwork with their general
compilation scheme for Prolog. This compilation scheme was first implemented in
SICStus Prolog by Holzbaur, and later further refined in HAL by Holzbaur, Garca
de la Banda et al. (2005) and in hProlog by Schrijvers and Demoen (2004b). The
latter system, called the K.U.Leuven CHR system, was subsequently ported to many
other Prolog systems and is currently available in XSB (Schrijvers, Warren et al.
2003; Schrijvers and Warren 2004), SWI-Prolog (Schrijvers, Wielemaker et al. 2005),
14
Fig. 5. A timeline of CHR implementations.
YAP, B-Prolog (using Action Rules; Schrijvers, Zhou et al. 2006), SICStus 4 and
Ciao Prolog. Another system directly based on the work of Holzbaur and Schrijvers
is the CHR library for SiLCC by Bouissou (2004). SiLCC is a programming language
based on linear logic and concurrent constraint programming. All of these systems
compile CHR programs to host language programs. The only available interpreter
for CHR(Prolog) is TOYCHR2.
Recently, systems with deviating operational semantics have been developed. The
CHRd system by Sarna-Starosta and Ramakrishnan (2007) runs in XSB, SWI-
Prolog and hProlog. It features a constraint store with set semantics and is par-
ticularly suitable for tabled execution. The CHRrp system by De Koninck, Stuckey
et al. (2008) for SWI-Prolog provides rule priorities.
2 by Gregory J. Duck, 2003. Download: http://www.cs.mu.oz.au/∼gjd/toychr/
15
4.1.2 CHR(FP)
As type checking is one of the most successful applications of CHR in the con-
text of Functional Programming (see Section 7.3.1), several CHR implementations
were developed specifically for this purpose. Most notable is the Chameleon system
(Stuckey and Sulzmann 2005) which features CHR as the programming language
for its extensible type system. Internally, Chameleon uses the HaskellCHR imple-
mentation3. The earlier HCHR prototype (Chin, Sulzmann et al. 2003) had a rather
heavy-weight and impractical approach to logical variables.
The aim of a 2007 Google Summer of Code project was to transfer this CHR
based type checking approach to two Haskell compilers (YHC and nhc98). The
project led to a new CHR interpreter for Haskell, called TaiChi (Boespflug 2007).
With the advent of software transactional memories (STM) in Haskell, two pro-
totype systems with parallel execution strategies have been developed: STMCHR4
and Concurrent CHR (Lam and Sulzmann 2007). These systems are currently the
only known CHR implementations that exploit the inherent parallelism in CHR
programs. Concurrent CHR also serves as the basis for Haskell-Join-Rules (Sulz-
mann and Lam 2007b) (cf. Section 6.1.2).
We also mention the Haskell library for the PAKCS implementation of the func-
tional logic language Curry (Hanus 2006). The PAKCS system actually compiles
Curry code to SICStus Prolog, and its CHR library is essentially a front-end for
the SICStus Prolog CHR library. The notable added value of the Curry front-end
is the (semi-)typing of the CHR code.
4.1.3 CHR(Java) and CHR(C)
Finally, CHR systems are available for both Java and C. These multiparadigmatic
integrations of CHR and mainstream programming languages offer powerful syn-
ergetic advantages to the software developer: they facilitate the development of
application-tailored constraint systems that cooperate efficiently with existing host
language components. For a detailed discussion on the different conceptual and
technical challenges encountered when embedding CHR into an imperative host
language, we refer to Van Weert, Wuille et al. (2008).
CHR(Java). There are at least four implementations of CHR in Java. The earliest is
the Java Constraint Kit (JaCK) by Abdennadher (2001) and others (Abdennadher,
Kramer et al. 2002). It consists of three major components:
1. JCHR (Schmauß 1999) — a CHR dialect intended to resemble Java, in order
to provide an intuitive programming experience. No operational semantics is
specified for this system, and its behavior deviates from other CHR imple-
mentations.
3 by Gregory J. Duck, 2004. Download: http://www.cs.mu.oz.au/∼gjd/haskellchr/ 4 by Michael Stahl, 2007. Download: http://www.cs.kuleuven.be/∼dtai/projects/CHR/
16
2. VisualCHR (Abdennadher and Saft 2001) — an interactive tool visualizing
the execution of JCHR (cf. Section 4.3). 3. JASE (Kramer 2001) — a “Java Abstract Search Engine” in which tree-based
search strategies can be specified. The JASE library is added to the JaCK
framework as an orthogonal component. It provides a number of utility classes
that aid the user to implement search algorithms in the Java host language.
A typical algorithm consists of the following two operations, executed in a
loop: a JCHR handler is run until it reaches a fix-point, after which a new
choice is made. If an inconsistency is found, backtracking is used to return to
the previous choice point. JASE aids in maintaining the search tree, and can
be configured to use either trailing or copying.
DJCHR (Dynamic JCHR; Wolf 2001a) is an implementation of adaptive CHR
(see Section 5.1.4). The incremental adaptation algorithm underlying DJCHR main-
tains justifications for rule applications and constraint additions. Wolf (2005) shows
that these justifications, and in particular those of any derived false constraint,
also serve as a basis for intelligent search strategies. As in JaCK, the different
search algorithms are implemented orthogonally to the CHR program. Wolf’s ap-
proach confirms that advanced search strategies are often more efficient than a
low-level, built-in implementation of chronological backtracking (as in Prolog).
The K.U.Leuven JCHR system (Van Weert, Schrijvers et al. 2005) addresses
the main issue of JaCK, its poor performance. The focus of K.U.Leuven JCHR is
on both performance and integration with the host language. K.U.Leuven JCHR
handlers integrate neatly with existing Java code, and it is currently one of the
most efficient CHR systems available. The current implementation does not feature
search capabilities.
Finally, the CHORD system (Constraint Handling Object-oriented Rules with
Disjunctive bodies)5, developed as part of the ORCAS project (Robin and Vitorino
2006), is a Java implementation of CHR∨ (Menezes, Vitorino et al. 2005).
CHR(C). CCHR (Wuille, Schrijvers et al. 2007) implements CHR for C. It is an
extremely efficient CHR system conforming to the ωr refined operational semantics.
It uses a syntax that is intuitive to both CHR adepts and imperative programmers.
4.2 Compilation
Considerable research has been conducted on the efficient compilation of CHR.
Section 4.2.1 provides an overview of the compilation schemes used by the different
CHR systems; Sections 4.2.2 and 4.2.3 survey existing analyses and optimizations.
4.2.1 Compilation Schemes
The first CHR compilation scheme, for ECLiPSe Prolog, was described by Fruhwirth
and Brisset (1995). Holzbaur and Fruhwirth (1999; 2000a) have adapted this scheme
5 by Jairson Vitorino and Marcos Aurelio, 2005, http://chord.sourceforge.net/
17
from ECLiPSe’s fairly specific suspension mechanism to the more primitive and flex-
ible attributed variables feature found in SICStus Prolog. The latter form has been
adopted by HALCHR, K.U.Leuven CHR, and was formalized in the refined opera-
tional semantics (Duck, Stuckey et al. 2004). A good overview of the compilation
scheme can be found in the Ph.D. theses of Duck (2005) and Schrijvers (2005), and
in (Van Weert, Wuille et al. 2008).
In its essence, the scheme maps each constraint to a procedure. Imposing the
constraint then corresponds to calling the procedure. This procedure puts the new
constraint in the constraint store datastructure, and attempts to fire rules involving
the new constraint. For the latter purpose, the scheme contains an occurrence pro-
cedure for each occurrence of the constraint symbol in a rule. The main constraint
procedure calls these occurrence procedures in the textual order of the rules. The
reactivation of a constraint is realized through calling the occurrence procedures
anew. Each procedure looks up the required additional constraints in the constraint
store datastructure and checks both the guard and propagation history. If all tests
succeed, the rule is committed to: an entry is added to the propagation history, the
appropriate matching constraints are removed from the constraint store and the
body of the rule is executed.
The Prolog compilation scheme is specifically designed for the built-in constraint
theory of Herbrand equations. Duck, Stuckey et al. (2003) show how it can be
extended to cover arbitrary constraint theories and solvers.
Schrijvers, Zhou et al. (2006) experimented with an action rules compilation
scheme in BProlog. However, capturing the intricate reactivation behavior of CHR’s
refined operational semantics turned out to be hard because the action rules’ be-
havior differs considerably on that account.
Lam and Sulzmann (2007) showed that software transactional memories (STM),
as supported by the Glasgow Haskell Compiler, are a good match for the concur-
rent implementation of CHR. Sulzmann and Lam (2007a) also explored the use
of Haskell’s laziness and concurrency abstractions for implementing the search of
partner constraints.
CHR(Java). Both JaCK (Schmauß 1999) and CHORD take a different approach
compared to most other CHR compilers. Their front-end transforms the CHR source
files to Java code that initializes the data structures of a generic runtime. CHR
programs are then essentially interpreted. No major optimizations are performed.
DJCHR uses a compilation scheme similar to the basic CHR(Prolog) scheme, but
extended with truth maintenance facilities required for adaptive constraint handling
(Wolf 2001a). Justifications for constraints and rule applications are implemented
efficiently using bit vectors. The runtime also implements adaptive unification and
entailment algorithms. Following the approach of Holzbaur and Fruhwirth (1999;
2000a), fast partner constraint retrieval is achieved using a form of attributed vari-
ables (Wolf 2001b).
K.U.Leuven JCHR and CCHR. The compilation schemes used by the K.U.Leuven
JCHR and CCHR systems (Van Weert, Schrijvers et al. 2005; Wuille, Schrijvers
18
et al. 2007) are based on the basic compilation scheme for CHR(Prolog), modified
to fit an imperative language (Van Weert, Wuille et al. 2008). Searching for partner
constraints is done through explicit iteration. Also, the data structures required
for the implementation of the constraint store are implemented more naturally and
efficiently in an imperative host language than in an LP language. An important
issue is that the host language typically cannot handle recursive calls efficiently. The
common CHR(Prolog) scheme was therefore adjusted significantly to avoid frequent
call stack overflows. The compilation scheme used by the K.U.Leuven JCHR system
is described in detail in (Van Weert 2008).
The CCHR compiler performs some limited optimizations, like memory reuse,
basic join ordering (see Section 4.2.2), as well as imperative-language specific opti-
mizations. The K.U.Leuven JCHR compiler implements most of the optimizations
mentioned in Section 4.2.2. For more details, see (Van Weert, Wuille et al. 2008).
CHRrp. A compilation scheme for CHRrp that is strongly based on the one for
regular CHR in Prolog, is presented in (De Koninck, Stuckey et al. 2008). It is
formalized in the refined priority semantics ωrp, which combines the refined opera-
tional semantics ωr of regular CHR, with the priority semantics ωp of CHRrp.
The main differences are the following. The initial goal, as well as rule bodies,
are executed in batch mode, i.e., no rule can fire as long as there are unprocessed
goal or body constraints (i.e., the Apply transition is not allowed if the Introduce
transition is applicable, cf. Fig. 4). New constraints are scheduled for activation at
all priorities at which they have occurrences, instead of being activated as soon
as they are processed. Constraints are activated at a given priority and as such
only consider those rules that share this priority. Finally, after each rule firing, it
is checked whether a scheduled constraint needs to be activated. To deal with so-
called dynamic priority rules, which are rules for which the actual priority is only
determined at runtime, a source-to-source transformation is given in (De Koninck,
Stuckey et al. 2008), that transforms these rules to the desired form for the ωrp
semantics.
4.2.2 Analysis and Optimizing Compilation
A number of (mostly static) analyses and optimizations have been proposed to
increase the performance of CHR systems (Holzbaur, Garca de la Banda et al.
2005; Schrijvers 2005; Duck 2005; Van Weert, Wuille et al. 2008). Without going
into the technical details, we very briefly discuss a list of recent optimizations:
Indexing. The efficient, selective lookup of candidate partner constraints is in-
dispensable for the efficient determination of matching rules. The traditional
CHR(Prolog) compilation scheme (see Section 4.2.1) uses attributed variables
for a constant time lookup of the constraints containing a known, unbound vari-
able. Holzbaur, Garca de la Banda et al. (2005) propose the use of a balanced
tree for the lookup of constraints via known ground arguments, which allows for
logarithmic worst-case time lookup. Schrijvers (2005) further improves this using
19
hash tables to get amortized constant time constraint store operations. Sneyers,
Schrijvers et al. (2006a) finally introduce array-based indexes to obtain correct
space and time complexity guarantees (see also (Sneyers, Schrijvers et al. 2009)).
Sarna-Starosta and Schrijvers (2007) show how indexing on compound term pat-
terns is reduced to the above indexing techniques via program transformation.
Abstract interpretation. Schrijvers, Stuckey et al. (2005) present a general and
systematic framework for program analysis of CHR for optimized compilation
based on abstract interpretation. Two instances are given: late storage analysis
(for reducing constraint store updates) and groundness analysis.
Functional dependencies. Functional dependency analysis (Duck and Schrijvers
2005) is a third instance of the abstract interpretation framework. It aims at
tracking the cardinality of constraints (zero, one or more) for specializing con-
straint store indexes and related operations.
Guard optimization. The guard optimization (Sneyers, Schrijvers et al. 2005) re-
moves redundant conjuncts in rule guards by reasoning on the ramifications of the
refined operational semantics. More precisely, non-applicability of rules contain-
ing earlier removed occurrences of a constraint, can be used to infer redundant
guard conditions.
Continuation optimization. The continuation optimization (Sneyers, Schrijvers
et al. 2005) uses a similar reasoning to skip occurrences that can never lead to
rule firings.
Delay avoidance. Schrijvers and Demoen (2004a) and Holzbaur, Garca de la
Banda et al. (2005) describe techniques for avoiding the unnecessary delay and
reactivation of constraints.
Memory reuse. Two memory optimizations (in-place updates and suspension reuse)
were introduced by Sneyers, Schrijvers et al. (2006b). They significantly reduce
the memory footprint and the time spent in garbage collection.
Join ordering. The time complexity of executing a CHR program is often deter-
mined by the join ordering — the order in which partner constraints are looked
up in order to find matching rules. Holzbaur, Garca de la Banda et al. (2005)
and Duck (2005) discussed ad-hoc heuristics for join ordering. De Koninck and
Sneyers (2007) proposed a more rigorous investigation.
4.2.3 Code Specialization and Transformation
Most of the optimizations in the previous section are not expressible as source-to-
source transformations. Like compiler optimization, program transformation can
also be used to improve performance. The first proposal for CHR source-to-source
transformation, by Fruhwirth (2005c), adds redundant, specialized rules to a CHR
program; these rules capture the effect of the original program for a particular goal.
In more recent work, Tacchella, Gabbrielli et al. (2007) adapt the conventional
notion of unfolding to CHR.
While the above study program transformation from a more theoretical point of
view, Sarna-Starosta and Schrijvers (2007) show that various program transforma-
tion techniques improve indexing performance.
20
Fruhwirth and Holzbaur (2003) propose to express CHR source-to-source trans-
formations in CHR itself, and they show how to implement various language ex-
tensions (such as probabilistic CHR) by transformation to plain CHR. Van Weert,
Sneyers et al. (2008) implemented an extension of CHR with aggregates (see Sec-
tion 5.2.2) using a similar approach, with a more expressive transformation lan-
guage.
4.3 Programming Environments
Over the past decade there has been an exponential increase in the number of CHR
systems (Section 4.1), and CHR compilation techniques have matured considerably
(Section 4.2). The support for advanced software development tools, such as debug-
gers, refactoring tools, and automated analysis tools, lags somewhat behind, and
remains an important challenge for the CHR community.
VisualCHR (Abdennadher and Saft 2001), part of JaCK (see Section 4.1.3), is
an interactive tool visualizing the execution of CHR rules. It can be used to debug
and to improve the efficiency of constraint solvers.
Both Holzbaur’s CHR implementation and the K.U.Leuven CHR system feature
a trace-based debugger that is integrated in the Prolog four port tracer. A generic
trace analysis tool, with an instantiation for CHR, is presented in (Ducasse 1999).
Checked type annotations are useful both for documentation and debugging pur-
poses. CHR systems with a typed host language commonly perform type checking,
or even type inference. The K.U.Leuven CHR system also allows optional type dec-
larations, with both dynamic and static type checking. Coquery and Fages (2005)
present a generic type system for CHR(H) (cf. also Section 7.3.1).
Ringwelski and Schlenker (2000a) propose the automatic inference of imported
and exported symbols of CHR solvers, and the composition of solvers by matching
up their interfaces (Ringwelski and Schlenker 2000b).
Schumann (2002) presents a literate programming system for CHR. The system
allows for generating from the same literate program source both an algorithm
specification typeset in LATEX using mathematical notation, and the corresponding
executable CHR source code.
Based on the theoretical results of Abdennadher, Fruhwirth et al. (1999) (see
Section 3.1), Bouissou (2004) implemented a confluence analyzer in CHR. Duck
(2005) presents and evaluates a confluence checker based on the refined operational
semantics. We do not know of any practical implementations of the other analyses
of Section 3.1.
5 Extensions and Variants
Over the years, weaknesses and limitations of CHR have been identified, for instance
regarding execution control, expressivity, modularity, incrementality, and search. In
this section we consider extensions and variants of CHR that were proposed to tackle
these issues.
5.1 Deviating Operational Semantics
We first discuss variants of CHR with an operational semantics that deviates from
the commonly used refined operational semantics discussed in Section 2.2.2.
5.1.1 Probabilistic CHR
Probabilistic CHR (PCHR; Fruhwirth, Di Pierro et al. 2002) extends CHR with
probabilistic choice between the applicable rules in any state (though only for a
given active constraint). It supports the implementation of algorithms like simulated
annealing, which is often used for constrained optimization. It also gives rise to
new concepts like probabilistic confluence and probabilistic termination. In PCHR,
the probabilities are either a fixed number or an arithmetic expression involving
variables that appear in the head. The latter are called parametrised probabilities.
The actual probability that a rule is executed in a given state is found by dividing
the rule probability by the sum of the probabilities of all fireable rule instances.
Fruhwirth, Di Pierro et al. (2002) give an implementation of PCHR by means of
a source-to-source transformation using the framework proposed by Fruhwirth and
Holzbaur (2003).
As a simple example, the following PCHR program simulates tossing a coin:
toss(Coin) <=>0.5: Coin=head.
toss(Coin) <=>0.5: Coin=tail.
Given a toss/1 constraint, one of the rules will be applied, with equal probability.
5.1.2 CHRd
The CHRd system (CHR with distributed constraint store) of Sarna-Starosta and
Ramakrishnan (2007) alleviates the limitations of conventional CHR systems for
efficient tabled evaluation encountered by Schrijvers and Warren (2004). For this
purpose it implements a set-based operational semantics, i.e. the constraint store
is a set rather than a multiset. Moreover, CHRd’s constraint store has no global
access point; constraints can only be retrieved through their logical variables. This
rules out (the efficient execution of) of ground CHR programs.
5.1.3 CHRrp
CHRrp (De Koninck, Schrijvers et al. 2007b) is CHR extended with user-definable
rule priorities. A rule’s priority is either a number or an arithmetic expression in-
volving variables that appear in the rule heads. The latter allows different instances
of a rule to be executed at different priorities. The following CHRrp-related top-
ics are dealt with in other sections: its operational semantics in Section 2.2.3; its
compilation schema in Section 4.2.1; and its implementation for SWI-Prolog in
Section 4.1.1.
An example that illustrates the power of dynamic priorities is the following
CHRrp implementation of Dijkstra’s algorithm:
22
1 :: dist(V,D1) \ dist(V,D2) <=> D1 =< D2 | true.
D+2 :: dist(V,D), edge(V,C,W) ==> dist(W,D+C).
The priority of the last rule makes sure that new distance labels are propagated in
the right order: first the nodes closest to the source node.
5.1.4 Adaptive CHR
Constraint solving in a continuously changing, dynamic environment often requires
immediate adaptation of the solutions, i.e. when constraints are added or removed.
By nature, CHR solvers already support efficient adaptation when constraints are
added. Wolf (1999; 2000) introduces an extended incremental adaptation algorithm
which is capable of adapting CHR derivations after constraint deletions as well.
This algorithm is further improved by Wolf (2000a) with the elimination of local
variables using early projection. An efficient implementation exists in Java (Wolf
2001a; 2001b; cf. Section 4.1.3).
Interesting applications of adaptive CHR include adaptive solving of soft con-
straints, discussed in Section 7.1, and the realization of intelligent search strategies,
discussed in Sections 4.1.3 and 5.2.1.
5.2 Language Extensions
We now discuss some additional language features that have been added to the
CHR language.
Most constraint solvers require search next to constraint simplification and propa-
gation. However pure CHR does not offer any support for search. Abdennadher and
Schutz (1998) propose a solution to this problem: an extension of CHR with dis-
junctions in rule bodies (see also Abdennadher 2000; 2001). The resulting language
is denoted CHR∨ (pronounced “CHR-or”), and is capable of expressing several
declarative evaluation strategies, including bottom-up evaluation, top-down evalu-
ation, model generation and abduction (see Section 7.3.2 for abduction). Any (pure)
Prolog program can be rephrased as an equivalent CHR∨ program (Abdennadher
2000; 2001). An interesting aspect of CHR∨ is that the extension comes for free
in CHR(Prolog) implementations by means of the built-in Prolog disjunction and
search mechanism.
As a typical example of programming in CHR∨, consider the following rule:
labeling, X::Domain <=> member(X,Domain), labeling.
Note the implicit disjunction in the call to the Prolog predicate member/2.
Various ways have been proposed to make the search in CHR∨ programs more
flexible and efficient. Menezes, Vitorino et al. (2005) present a CHR∨ implementa-
tion for Java in which the search tree is made explicit and manipulated at runtime
23
to improve efficiency. The nodes in the search tree can be reordered to avoid re-
dundant work. De Koninck, Schrijvers et al. (2006b) extend both the theoretical
and refined operational semantics of CHR towards CHR∨. The theoretical ver-
sion leaves the search strategy undetermined, whereas the refined version allows
the specification of various search strategies. In the same work, an implementation
for different strategies in CHR(Prolog) is realized by means of a source-to-source
transformation.
For CHR(Java) systems, unlike for CHR(LP) systems, the host language does not
provide search capabilities. The flexible specification of intelligent search strategies
has therefore received considerable attention in several CHR(Java) systems (Kramer
2001; Wolf 2005). As described in Section 4.1.3, in these systems, the search strate-
gies are implemented and specified in the host language itself, orthogonally to the
actual CHR program. Wolf, Robin et al. (2007) propose an implementation of CHR∨
using the ideas of (Wolf 2005), in order to allow a more declarative formulation of
search in the bodies of CHR rules, while preserving efficiency and flexibility. A re-
fined operational semantics of the proposed execution strategy is presented as well.
Along these lines is the approach proposed by Robin, Vitorino et al. (2007), where
disjunctions in CHR∨ are transformed into special purpose constraints that can be
handled by an external search component such as JASE (Kramer 2001).
5.2.2 Negation and Aggregates
CHR programmers often want to test for the absence of constraints. CHR was
therefore extended with negation as absence by Van Weert, Sneyers et al. (2006).
Negation as absence was later generalized to a much more powerful language fea-
ture, called aggregates (Sneyers, Van Weert et al. 2007). Aggregates accumulate
information over unbounded portions of the constraint store. Predefined aggregates
include sum, count, findall, and min. The proposed extension also features nested
aggregate expressions over guarded conjunctions of constraints, and application-
tailored user-defined aggregates. Aggregates lead to increased expressivity and more
concise programs. An implementation based on source-to-source transformations
(Van Weert, Sneyers et al. 2008) is available. The implementation uses efficient
incremental aggregate computation, and empirical results show that the desired
runtime complexity is attainable with an acceptable constant time overhead.
As an example of nested aggregate expressions, consider the following rule:
eulerian, forall(node(N),(
count(edge(N,_),X), count(edge(_,N),X)
)) <=> writeln(graph_is_eulerian).
The above rule is applicable if for every constraint node(N), the number of out-
going edges in N equals the number of incoming edges (i.e. if the first number is X,
the other number must also be X).
24
5.3 Solver Hierarchies
While the theory of the CHR language generally considers arbitrary built-in solvers,
traditional CHR implementations restrict themselves to the Herbrand equality con-
straint solver, with very little, if any, support for other constraint solvers.
Duck, Stuckey et al. (2003) show how to build CHR solvers on top of arbitrary
built-in constraint solvers by means of ask constraints. The ask constraints signal
the CHR solver when something has changed in the built-in store with respect to
variables of interest. Then the relevant CHR constraints may be reactivated.
Schrijvers, Demoen et al. (2006) provide an automated means for deriving ask
versions of CHR constraints. In this way full hierarchies of constraint solvers can
be written in CHR, where one CHR solver serves as the built-in solver for another
CHR solver.
6 Relation to Other Formalisms
The relation of CHR to other formalisms has recently received quite a lot of atten-
tion. In this section we give a brief overview.
As a general remark, we should mention that most of the formalisms related to
CHR are limited to ground terms and lack the equivalent of propagation rules. In
that sense, they are subsumed by CHR. Also, CHR can be seen as an instance or
a generalization of concurrent constraint programming, constraint logic program-
ming, constraint databases, and deductive databases.
Logical formalisms. In Section 2.1, we discussed the logical semantics of CHR. CHR
can be given a classical logic semantics (Fruhwirth 1998), a linear logic semantics
(Betz and Fruhwirth 2005; 2007), and a transaction logic semantics (Meister, Djel-
loul et al. 2007). Also, it should be noted that CHR∨ subsumes Prolog. Frame-
Logic (F-Logic) is an object-oriented extension of classical predicate logic. Kaser
and Meister (2006) explore the relation between CHR and F-Logic by implementing
(a fragment of) F-Logic in CHR.
Term rewriting. CHR can be considered as associative and commutative (AC) term
rewriting of flat conjunctions. The term rewriting literature inspired many results
for CHR, for example on confluence (see Section 3.1) and termination (see Sec-
tion 3.2). Recently, Duck, Stuckey et al. (2006) proposed the formalism of ACD
term rewriting, which subsumes both AC term rewriting and CHR.
6.1 Set-Based Formalisms
Numerous formalisms have been proposed that are based on (multi-)set rewriting.
6.1.1 Production Rules / Business Rules
Production rules, or business rules as they are now often called, is a rule-based
paradigm closely related to CHR. Classic matching algorithms, such as RETE and
25
LEAPS, have influenced early work on CHR compilation. Production rules have also
inspired the research towards extending CHR with aggregates (see Section 5.2.2).
6.1.2 Join-Calculus
The join-calculus is a calculus for concurrent programming, with both stand-alone
implementations and extensions of general purpose languages, such as JoCaml
(OCaml), Join Java and Polyphonic C#.
Sulzmann and Lam (2007b) propose a Haskell language extension for support-
ing join-calculus-style concurrent programming, based on CHR. Join-calculus rules,
called chords, are essentially guardless simplification rules with linear match pat-
terns. In a linear pattern, different head conjuncts are not allowed to share variables.
Hence, CHR offers considerably increased expressivity over the join-calculus: prop-
agation rules, general guards and non-linear patterns.
6.1.3 Logical Algorithms
As already mentioned in Section 3.3.2, CHR is strongly related to the Logical Algo-
rithms (LA) formalism by Ganzinger and McAllester (2002). De Koninck, Schrijvers
et al. (2007a) have showed how LA programs can easily be translated into CHRrp
programs. The opposite only holds for a subset of CHRrp since the LA language
lacks the ability to plug in any built-in constraint theory, and also only supports
ground constraints (called assertions in LA terminology). The correspondence be-
tween both languages makes it possible to apply the meta-complexity result for LA
to a subset of CHRrp as explained in Section 3.3.2. It is also interesting that the
first actual implementation of LA is that of De Koninck, Schrijvers et al. (2007a),
which compiles the language into (regular) CHR rules.
6.1.4 Equivalent Transformation Rules
The Equivalent Transformation (ET) computation model is a rewriting system
which consists of the application of conditional multi-headed multi-body ET rules
(ETR). Although CHR and ETR are similar in syntax, they have different the-
oretical bases: CHR is based on logical equivalence of logical formulas, whereas
ETR is based on the set equivalence of descriptions. Shigeta, Akama et al. (2006)
investigate the relation between CHR and ETR.
6.2 Graph-Based Formalisms
Recently, CHR has also been related to a number of graph-based formalisms:
6.2.1 Graph Transformation Systems
Raiser (2007) describes an elegant embedding of Graph Transformation Systems
(GTS) in CHR. The confluence properties (see Section 3.1) for CHR and GTS are
26
similar; in particular, a sufficient criterion for confluence of a GTS is the confluence
of the corresponding CHR program. Using a slightly weaker notion of confluence of
CHR (in the spirit of observable confluence; Duck, Stuckey et al. 2007), standard
CHR confluence checkers can be reused to decide GTS confluence.
6.2.2 Petri Nets
Petri nets are a well-known formalism for the modeling and analysis of concurrent
processes. Betz (2007) provides a first study of the relation between CHR and
Petri nets. He provides a sound and complete translation of place/transition nets
(P/T nets) — a standard variant of Petri nets — into a small segment of CHR.
P/T nets are, unlike CHR (cf. Section 3.3), not Turing complete. A translation
of a significant subsegment of CHR into colored Petri nets is presented as well by
Betz (2007). This work is a promising first step towards cross-fertilization between
both formalisms. Results from Petri nets could for instance be applied to analyze
concurrency properties of CHR programs.
6.2.3 LMNtal
LMNtal (Ueda et al. 2006) is a language based on hierarchical graph rewriting which
intends to unify constraint-based concurrency and CHR. It uses logical variables to
represent connectivity and so-called membranes to represent hierarchy. Flat LMNtal
rules (rules without membranes) can be seen as simplification rules in CHR.
7 Applications
The main application domain considered in the previous CHR survey (Fruhwirth
1998) is the development of constraint solvers. It also discusses two other applica-
tions of CHR in some depth. The first one is related to the problem of finding an
optimal placement of wireless transmitters (Fruhwirth and Brisset 1998; 2000); the
second one is an expert system for estimating the maximum fair rent in the city of
Munich, called the Munich Rent Advisor (Fruhwirth and Abdennadher 2001). In
this section, we give an overview of more recent applications of CHR.
7.1 Constraint Solvers
CHR was originally designed specifically for writing constraint solvers. We discuss
some recent examples of constraint solvers written in CHR. The following exam-
ples illustrate how CHR can be used to build effective prototypes of non-trivial
constraint solvers:
Lexicographic order. Fruhwirth (2006a) presented a constraint solver for a lexi-
cographic order constraint in terms of inequality constraints offered by the under-
lying solver. The approach is general in that it can be used for any constraint do-
main offering inequality (less-than) constraints between problem variables. Still,
the program is very concise and elegant; it consists of just six rules.
27
Rational trees. Meister, Djelloul et al. (2006) presented a solver for existentially
quantified conjunctions of non-flat equations over rational trees. The solver con-
sists of a transformation to flat equations, after which a classic CHR solver for
rational trees can be used. This results in a complexity improvement with respect
to previous work. In (Djelloul, Dao et al. 2007), the solver for rational trees is
used as part of a more general solver for (quantified) first-order constraints over
finite and infinite trees.
Sequences. Kosmatov (2006a; 2006b) has constructed a constraint solver for se-
quences, inspired by an earlier solver for lists by Fruhwirth. The solver expresses
many sequence constraints in terms of two basic constraints, for sequence con-
catenation and size.
Non-linear constraints. A general purpose CHR-based CLP system for non-
linear (polynomial) constraints over the real numbers was presented by De Kon-
inck, Schrijvers et al. (2006a). The system, called INCLP(R), is based on interval
arithmetic and uses an interval Newton method as well as constraint inversion to
achieve respectively box and hull consistency.
Interactive constraint satisfaction. Alberti, Gavanelli et al. (2005) describe
the implementation of a CLP language for expressing Interactive Constraint Sat-
isfaction Problems (ICSP). In the ICSP model incremental constraint propaga-
tion is possible even when variable domains are not fully known, performing
acquisition of domain elements only when necessary.
Solvers derived from union-find. Fruhwirth (2006b) proposes linear-time algo-
rithms for solving certain boolean equations and linear polynomial equations in
two variables. These solvers are derived from the classic union-find algorithm (see
Section 7.2).
In the rest of this subsection we discuss, in a bit more detail, some typical appli-
cation domains in which CHR has been used to implement constraint solvers.
7.1.1 Soft Constraints and Scheduling
An important class of constraints are the so-called soft constraints which are used
to represent preferences amongst solutions to a problem. Unlike hard (required)
constraints which must hold in any solution, soft (preferential) constraints must only
be satisfied as far as possible. Bistarelli, Fruhwirth et al. (2004) present a series of
constraint solvers for (mostly) extensionally defined finite domain soft constraints,
based on the framework of c-semirings. In this framework, soft constraints can be
combined and projected onto a subset of their variables, by using the two operators
of a c-semiring. A node and arc consistency solver is presented, as well as complete
solvers based on variable elimination or branch and bound optimization.
Another well-known formalism for describing over-constrained systems is that
of constraint hierarchies, where constraints with hierarchical strengths or prefer-
ences can be specified, and non-trivial error functions can be used to determine
the solutions. Wolf (2000b) proposes an approach for solving dynamically changing
constraint hierarchies. Constraint hierarchies over finite domains are transformed
28
into equivalent constraint systems, which are then solved using an adaptive CHR
solver (Wolf, Gruenhagen et al. 2000; Wolf 2001a; see Section 5.1.4).
Scheduling. Abdennadher and Marte (2000) have successfully used CHR for schedul-
ing courses at the university of Munich. Their approach is based on a form of soft
constraints, implemented in CHR, to deal with teacher’s preferences. A related
problem, namely that of assigning classrooms to courses given a timetable, is dealt
with by Abdennadher, Saft et al. (2000). An overview of both applications is found
in (Abdennadher 2001).
7.1.2 Spatio-Temporal Reasoning
In the context of autonomous mobile robot navigation, a crucial research topic
is automated qualitative reasoning about spatio-temporal information, including
orientation, named or compared distances, cardinal directions, topology and time.
The use of CHR for spatio-temporal reasoning has received considerable research
attention. We mention in particular the contributions of Escrig et al. (Escrig and
Toledo 1998a; 1998b; Cabedo and Escrig 2003).
Meyer (2000) has applied CHR for the constraint-based specification and im-
plementation of diagrammatic environments. Grammar-based specifications of dia-
grammatic objects are translated to directly executable CHR rules. This approach
is very powerful and flexible. The use of CHR allows the integration with other
constraint domains, and additional CHR rules can easily be added to model more
complex diagrammatic systems. Similar results are obtained with CHRG in the
context of natural language processing (see Section 7.3.3).
7.1.3 Multi-Agent Systems
FLUX (Thielscher 2002; 2005) is a high-level programming system, implemented
in CHR and based on fluent calculus, for cognitive agents that reason logically
about actions in the context of incomplete information. An interesting application
of this system is FLUXPLAYER (Schiffel and Thielscher 2007), which won the 2006
General Game Playing (GGP) competition at AAAI’06. Seitz, Bauer et al. (2002)
and Alberti et al. (2004; 2004; 2006) also applied CHR in the context of multi-agent
systems.
Lam and Sulzmann (2006) explore the use of CHR as an agent specification lan-
guage, founded on CHR’s linear logic semantics (see Section 2.1.2). They introduce
a monadic operational semantics for CHR, where special action constraints have
to be processed in sequence. They reason about the termination and confluence
properties of the resulting language. They were also the first to propose the use of
invariants for CHR confluence testing, an approach that was later formalized by
Duck, Stuckey et al. (2007) — cf. Section 3.1.
29
7.1.4 Semantic Web and Web 3.0
One of the core problems related to the so-called Semantic Web is the integration
and combination of data from diverse information sources. Bressan and Goh (1998)
describe an implementation of the coin (context interchange) mediator that uses
CHR for solving integrity constraints. In more recent work, CHR is used for im-
plementing an extension of the coin framework, capable of handling more data
source heterogeneity (Firat 2003). Badea, Tilivea et al. (2004) present an improved
mediator-based integration system. It allows forward propagation rules involving
model predicates, whereas coin only allows integrity constraints on source predi-
cates.
The Web Ontology Language (OWL) is based on Description Logic (DL). Various
rule-based formalisms have been considered for combination and integration with
OWL or other description logics. Fruhwirth (2007) proposes a CHR-based approach
to DL and DL rules. Simply encoding the first-order logic theory of the DL in
CHR results in a concise, correct, confluent and concurrent CHR program with
performance guarantees.
The Cuypers Multimedia Transformation Engine (Geurts, van Ossenbruggen
et al. 2001) is a prototype system for automatic generation of Web-based presenta-
tions adapted to device-specific capabilities and user preferences. It uses CHR and
traditional CLP to solve qualitative and quantitative spatio-temporal constraints.
7.1.5 Automatic Generation of Solvers
Many authors have investigated the automatic generation of CHR rules, constitut-
ing a constraint solver, from a formal specification. Most authors consider exten-
sionally defined constraints over (small) finite domains as the specification.
A first line of work is that of Apt and Monfroy (2001). From an extensional
definition of a finite domain constraint, a set of propagation rules is derived. These
rules reduce the domain of one variable based on the domains of the other variables
involved in the same constraint. As an extension, Brand and Monfroy (2003) propose
to transform the derived rules to obtain stronger propagation rules. This technique
is useful to obtain derived versions of constraints, such as the conjunction of two
constraints.
A second line of work is that of Abdennadher and Rigotti. In (2004) they de-
rive propagation rules from extensionally defined constraints. There are two main
differences with the previous line of work. Firstly, the rules are assembled from
given parts, and, secondly, propagation rules are transformed into simplification
rules when valid. This algorithm is implemented by the Automatic Rule Miner
tool (Abdennadher, Olama et al. 2006). They extend their approach to intensional
constraint definitions, where constraints are defined by logic programs (2005), and
further to symbolically derive rules from the logic programs, rather than from given
parts (2008).
Brand (2002) has proposed a method to eliminate redundant propagation rules
30
and applies it to rules generated by RuleMiner: one of the algorithms that forms
the basis of the Automatic Rule Miner tool by Abdennadher et al. (2006).
7.2 Union-Find and Other Classic Algorithms
CHR is used increasingly as a general-purpose programming language. Starting a
trend of investigating this side of CHR, Schrijvers and Fruhwirth (2005a; 2006)
implemented and analyzed the classic union-find algorithm in CHR. In particular,
they showed how the optimal complexity of this algorithm can be achieved in CHR
— a non-trivial achievement since this is believed to be impossible in pure Prolog.
This work lead to parallel versions of the union-find algorithm (Fruhwirth 2005b)
and several derived algorithms (Fruhwirth 2006b). Inspired by the specific optimal
complexity result for the union-find algorithm, Sneyers, Schrijvers et al. (2009) have
generalized this to arbitrary (RAM-machine) algorithms (see Section 3.3.2).
The question of finding elegant and natural implementations of classic algorithms
in CHR remains nevertheless an interesting research topic. Examples of recent work
in this area are implementations of Dijkstra’s shortest path algorithm using Fi-
bonacci heaps (Sneyers, Schrijvers et al. 2006a) and the preflow-push maximal flow
algorithm (Meister 2006).
7.3 Programming Language Development
Another application area in which CHR has proved to be useful is the devel-
opment of programming languages. CHR has been applied to implement addi-
tional programming language features such as type systems (Section 7.3.1), meta-
programming (Section 7.3.4), and abduction (Section 7.3.2). Also, CHR has been
used to implement new programming languages, especially in the context of com-
putational linguistics (Section 7.3.3). Finally, CHR has been used for testing and
verification (Section 7.3.5).
7.3.1 Type Systems
CHR’s aptness for symbolic constraint solving has led to many applications in the
context of type system design, type checking and type inference. While the basic
Hindley-Milner type system requires no more than a simple Herbrand equality
constraint, more advanced type systems require custom constraint solvers.
Alves and Florido (2002) presented the first work on using Prolog and CHR for
implementing the type inference framework HM(X), i.e. type inference for exten-
sions of the Hindley-Milner type system. This work was followed up by TypeTool
(Simoes and Florido 2004), a tool for visualizing the type inference process.
The most successful use of CHR in this area is for Haskell type classes. Type
classes are a principled approach to ad hoc function overloading based on type-level
constraints. By defining these type class constraints in terms of a CHR program
(Stuckey and Sulzmann 2005) the essential properties of the type checker (sound-
ness, completeness and termination) can easily be established. Moreover, various
31
extensions, such as multi-parameter type classes (Sulzmann, Schrijvers et al. 2006)
and functional dependencies (Sulzmann, Duck et al. 2007) are easily expressed. At
several occasions Sulzmann argues for HM(CHR), where the programmer can di-
rectly implement custom type system extensions in CHR. Wazny