CHR for Imperative Host Languages [chapter]

Peter Van Weert, Pieter Wuille, Tom Schrijvers, Bart Demoen
2008 Lecture Notes in Computer Science  
In this paper, we address the different conceptual and technical difficulties encountered when embedding CHR into an imperative host language. We argue that a tight, natural integration leads to a powerful programming language extension, intuitive to both CHR and imperative programmers. We show how to compile CHR to highly optimized imperative code. To this end, we first review the well-established CHR compilation scheme, and survey the large body of possible optimizations. We then show that
more » ... s scheme, when used for compilation to imperative target languages, leads to stack overflows. We therefore introduce new optimizations that considerably improve the performance of recursive CHR programs. Rules written using tail calls are even guaranteed to run in constant space. We implemented systems for both Java and C, following the language design principles and compilation scheme presented in this paper, and show that our implementations outperform other state-of-the-art CHR compilers by several orders of magnitude. Research Assistant of the Research Foundation -Flanders (FWO-Vlaanderen). Post-Doctoral Researcher of the Research Foundation-Flanders (FWO-Vlaanderen). Preliminaries: CHR Syntax and Semantics CHR is embedded in a host language that provides a number of predefined constraints, called built-in constraints, and a number of data types. The tradi- Fig. 1. The CHR program leq, a handler for the less-than-or-equal constraint. Informal Semantics An execution starts from an initial query: a sequence of constraints, given by the user. The multiset of all CHR constraints of a CHR handler is called its constraint store. The execution proceeds by applying, or firing, the handler's rules. A rule is applicable if there are constraints matching the rule's occurrences present in the constraint store for which the guard condition holds. When no more rules can be applied, the execution stops; the final constraint store is called the solution. Rules modify the constraint store as follows. A simplification rule removes the constraints that matched its head, and replaces them with those in its body. The double arrow indicates that the head is logically equivalent to the body, which justifies the replacement. Often, 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). As the body is implied by the head, it is redundant. However, adding redundant constraints may allow more rewriting later on. Simpagation rules are a hybrid between simplification and propagation rules: only the constraints matching its removed occurrences, i.e. those after the backslash, are removed if the rule is applied. Example 2. The first rule of the leq handler of Fig. 1 , reflexivity, replaces a leq(X,X) constraint by the trivial built-in constraint true. Operationally, this entails removing this constraint from the constraint store. The antisymmetry rule states that leq(X,Y) and leq(Y,X) are logically equivalent to X = Y. When firing this rule, the two constraints matching the left-hand side are removed from the store, after which the built-in equality constraint solver is told that X and Y are equal. The third rule, idempotence, removes redundant copies of the same leq constraint. It is necessary to do this explicitly since CHR has a multiset semantics: multiple instances of the same constraint can reside in the constraint store at the same time. The last rule, transitivity, is a propagation rule that computes the transitive closure of the leq relation. The Refined Operational Semantics The operational semantics introduced informally in the previous section corresponds to the so-called high-level or theoretical operational semantics of CHR [20, 26] . In this highly non-deterministic semantics, rules are applied in arbitrary order. Most CHR systems though implement a particular, significantly more deterministic instance of this semantics, called the refined operational semantics [20] . This semantics is commonly denoted by ω r . In ω r , queries and bodies are 1. Solve [b|A], S0 S1, B, T n S1 ++ A, S0 S1, b ∧ B, T n where b is a built-in constraint and vars(S0) ⊆ f ixed(B), the variables fixed by B. This causes all CHR constraints affected by the newly added built-in constraint b to be reconsidered.
doi:10.1007/978-3-540-92243-8_7 fatcat:m2ahjezy6rhcjouygrhg43save