Constraint handling rules for a given constraint system can often be derived from its definition in formalisms such as inference rules, rewrite rules, sequents, formulas expressing axioms and theorems. CHRs can also be found by first considering special cases of each constraint and then looking at interactions of pairs of constraints sharing a variable. Cases that don't occur in the application can be ignored. CHRs can also improve application programs by turning certain predicates into constraints to provide ``short-cuts'' (lemmas). For example, to the predicate append/3 one can add append(L1,[],L2) <=> L1=L2 together with label_with append(L1,L2,L3) if true.
Starting from an executable specification, the rules can then be refined and adapted to the specifics of the application. Efficiency can be improved by strengthening or weakening the guards to perform simplification as early as needed and to do the ``just right'' amount of propagation. Propagation rules can be expensive, because no constraints are removed. If the speed of the final handler is not satisfactory, it can be rewritten using meta-terms or auxiliary C functions.
The rules for a constraint can be scattered across the chr file as long as they are in the same module. The rules are tried in some order determined by the CHR compiler. Due to optimizations this order is not necessarily the textual order in which the rules where written. In addition, the incremental addition of constraints at run-time causes constraints to be tried for application of rules in some dynamically determined order.