1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872
|
\chapter{CHR: Constraint Handling Rules} \label{sec:chr}
This chapter is written by Tom Schrijvers, K.U. Leuven, and adjustments by
Jan Wielemaker.
The CHR system of SWI-Prolog is the {\em K.U.Leuven CHR system}. The runtime
environment is written by Christian Holzbaur and Tom Schrijvers while the
compiler is written by Tom Schrijvers. Both are integrated with SWI-Prolog
and licensed under compatible conditions with permission from the authors.
The main reference for the K.U.Leuven CHR system is:
\begin{itemize}
\item T. Schrijvers, and B. Demoen, {\em The K.U.Leuven CHR System: Implementation
and Application}, First Workshop on Constraint Handling Rules: Selected
Contributions (Fr\"uhwirth, T. and Meister, M., eds.), pp. 1--5, 2004.
\end{itemize}
On the K.U.Leuven CHR website (\url{http://dtai.cs.kuleuven.be/CHR/})
you can find more related papers, references and example programs.
\section{Introduction to CHR} \label{sec:chr-intro}
%=====================
Constraint Handling Rules (CHR) is a committed-choice rule-based language
embedded in Prolog. It is designed for writing constraint solvers and is
particularly useful for providing application-specific constraints.
It has been used in many kinds of applications, like scheduling,
model checking, abduction, and type checking, among many others.
CHR has previously been implemented in other Prolog systems (SICStus,
Eclipse, Yap), Haskell and Java. This CHR system is based on the
compilation scheme and runtime environment of CHR in SICStus.
In this documentation we restrict ourselves to giving a short overview
of CHR in general and mainly focus on elements specific to this
implementation. For a more thorough review of CHR we refer the reader to
\cite{Freuhwirth:2009}. More background on CHR can be found at
\cite{chrSite}.
In \secref{chr-syntaxandsemantics} we present the syntax of CHR in
Prolog and explain informally its operational semantics. Next,
\secref{practical} deals with practical issues of writing and compiling
Prolog programs containing CHR. \Secref{chr-debugging} explains the
(currently primitive) CHR debugging facilities. \Secref{chr-debug-preds}
provides a few useful predicates to inspect the constraint store, and
\secref{chr-examples} illustrates CHR with two example programs.
\Secref{chr-compatibility} describes some compatibility issues with
older versions of this system and SICStus' CHR system. Finally,
\secref{chr-guidelines} concludes with a few practical guidelines for
using CHR.
\section{CHR Syntax and Semantics} \label{sec:chr-syntaxandsemantics}
%=============================
\subsection{Syntax of CHR rules}
\label{sec:chr-syntax}
%-----------------
\begin{code}
rules --> rule, rules ; [].
rule --> name, actual_rule, pragma, [atom('.')].
name --> atom, [atom('@')] ; [].
actual_rule --> simplification_rule.
actual_rule --> propagation_rule.
actual_rule --> simpagation_rule.
simplification_rule --> head, [atom('<=>')], guard, body.
propagation_rule --> head, [atom('==>')], guard, body.
simpagation_rule --> head, [atom('\')], head, [atom('<=>')],
guard, body.
head --> constraints.
constraints --> constraint, constraint_id.
constraints --> constraint, constraint_id,
[atom(',')], constraints.
constraint --> compound_term.
constraint_id --> [].
constraint_id --> [atom('#')], variable.
constraint_id --> [atom('#')], [atom('passive')] .
guard --> [] ; goal, [atom('|')].
body --> goal.
pragma --> [].
pragma --> [atom('pragma')], actual_pragmas.
actual_pragmas --> actual_pragma.
actual_pragmas --> actual_pragma, [atom(',')], actual_pragmas.
actual_pragma --> [atom('passive(')], variable, [atom(')')].
\end{code}
Note that the guard of a rule may not contain any goal that binds a variable
in the head of the rule with a non-variable or with another variable in the
head of the rule. It may, however, bind variables that do not appear in the
head of the rule, e.g. an auxiliary variable introduced in the guard.
\subsection{Semantics of CHR}
\label{sec:chr-semantics}
%--------------------
In this subsection the operational semantics of CHR in Prolog are presented
informally. They do not differ essentially from other CHR systems.
When a constraint is called, it is considered an active constraint and
the system will try to apply the rules to it. Rules are tried and executed
sequentially in the order they are written.
A rule is conceptually tried for an active constraint in the following
way. The active constraint is matched with a constraint in the head of
the rule. If more constraints appear in the head, they are looked for
among the suspended constraints, which are called passive constraints in
this context. If the necessary passive constraints can be found and all
match with the head of the rule and the guard of the rule succeeds, then
the rule is committed and the body of the rule executed. If not all the
necessary passive constraints can be found, or the matching or the
guard fails, then the body is not executed and the process of trying and
executing simply continues with the following rules. If for a rule
there are multiple constraints in the head, the active constraint will
try the rule sequentially multiple times, each time trying to match with
another constraint.
This process ends either when the active constraint disappears, i.e.\ it
is removed by some rule, or after the last rule has been processed. In
the latter case the active constraint becomes suspended.
A suspended constraint is eligible as a passive constraint for an active
constraint. The other way it may interact again with the rules is when
a variable appearing in the constraint becomes bound to either a non-variable
or another variable involved in one or more constraints. In that case the
constraint is triggered, i.e.\ it becomes an active constraint and all
the rules are tried.
\paragraph{Rule Types}
%- - - - - - - - - -
There are three different kinds of rules, each with its specific semantics:
\begin{itemlist}
\item [simplification]
The simplification rule removes the constraints in its head and calls its body.
\item [propagation]
The propagation rule calls its body exactly once for the constraints in
its head.
\item [simpagation]
The simpagation rule removes the constraints in its head after the
$\backslash$ and then calls its body. It is an optimization of
simplification rules of the form: \[constraints_1, constraints_2 <=>
constraints_1, body \] Namely, in the simpagation form: \[ constraints_1
\backslash constraints_2 <=> body \] The $\mathit{constraints}_1$
constraints are not called in the body.
\end{itemlist}
\paragraph{Rule Names}
%- - - - - - - - - -
Naming a rule is optional and has no semantic meaning. It only functions
as documentation for the programmer.
\paragraph{Pragmas}
%- - - - - - - - -
The semantics of the pragmas are:
\begin{description}
\termitem{passive}{Identifier}
The constraint in the head of a rule \arg{Identifier} can only match a
passive constraint in that rule.
There is an abbreviated syntax for this pragma. Instead of:
\begin{code}
..., c # Id, ... <=> ... pragma passive(Id)
\end{code}
you can also write
\begin{code}
..., c # passive, ... <=> ...
\end{code}
\end{description}
Additional pragmas may be released in the future.
\begin{description}
\directive{chr_option}{2}{+Option, +Value}
It is possible to specify options that apply to all the CHR rules in the module.
Options are specified with the \texttt{chr_option/2} declaration:
\begin{code}
:- chr_option(Option,Value).
\end{code}
and may appear in the file anywhere after the first constraints declaration.
Available options are:
\begin{description}
\termitem{check_guard_bindings}{}
This option controls whether guards should be checked for (illegal) variable
bindings or not. Possible values for this option are \texttt{on} to enable
the checks, and \texttt{off} to disable the checks. If this option is on,
any guard fails when it binds a variable that appears in the head of the rule.
When the option is off (default), the behaviour of a binding in the guard is undefined.
\termitem{optimize}{}
This option controls the degree of optimization.
Possible values are \texttt{full} to enable all available
optimizations, and \texttt{off} (default) to disable all optimizations.
The default is derived from the SWI-Prolog flag \prologflag{optimise}, where
\const{true} is mapped to \const{full}. Therefore the command line
option \cmdlineoption{-O} provides full CHR optimization.
If optimization is enabled, debugging must be disabled.
\termitem{debug}{}
This option enables or disables the possibility to debug the CHR code.
Possible values are \texttt{on} (default) and \texttt{off}. See
\secref{chr-debugging} for more details on debugging. The default is
derived from the Prolog flag \prologflag{generate_debug_info}, which
is \const{true} by default. See \cmdlineoption{--no-debug}.
If debugging is enabled, optimization must be disabled.
\end{description}
\end{description}
% The above mode, type_declaration and type_definition options are deprecated.
% The new syntax is described below.
\section{CHR in SWI-Prolog Programs} \label{sec:practical}
%===========================
\subsection{Embedding CHR in Prolog Programs}
\label{sec:chr-embedding}
The CHR constraints defined in a \fileext{pl} file are
associated with a module. The default module is \const{user}. One should
never load different \fileext{pl} files with the same CHR module name.
\subsection{CHR Constraint declaration}
\label{sec:chr-declarations}
\begin{description}
\directive{chr_constraint}{1}{+Specifier}
Every constraint used in CHR rules has to be declared with a
chr_constraint/1 declaration by the {\em constraint specifier}. For
convenience multiple constraints may be declared at once with the same
\predref{chr_constraint}{1} declaration followed by a comma-separated
list of constraint specifiers.
A constraint specifier is, in its compact form, \texttt{$F$/$A$} where
$F$ and $A$ are respectively the functor name and arity of the
constraint, e.g.:
\begin{code}
:- chr_constraint foo/1.
:- chr_constraint bar/2, baz/3.
\end{code}
In its extended form, a constraint specifier is
\texttt{$c$($A_1$,\ldots,$A_n$)} where $c$ is the constraint's functor,
$n$ its arity and the $A_i$ are argument specifiers. An argument
specifier is a mode, optionally followed by a type. Example:
\begin{code}
:- chr_constraint get_value(+,?).
:- chr_constraint domain(?int, +list(int)),
alldifferent(?list(int)).
\end{code}
\end{description}
\paragraph{Modes}
A mode is one of:
\begin{description}
\termitem{-}{} The corresponding argument of every occurrence
of the constraint is always unbound.
\termitem{+}{} The corresponding argument of every occurrence
of the constraint is always ground.
\termitem{?}{} The corresponding argument of every occurrence
of the constraint can have any instantiation, which may change
over time. This is the default value.
\end{description}
\paragraph{Types}
A type can be a user-defined type or one of the built-in types. A type
comprises a (possibly infinite) set of values. The type declaration for a
constraint argument means that for every instance of that constraint the
corresponding argument is only ever bound to values in that set. It does not
state that the argument necessarily has to be bound to a value.
The built-in types are:
\begin{description}
\termitem{int}{} The corresponding argument of every occurrence
of the constraint is an integer number.
\termitem{dense_int}{} The corresponding argument of every occurrence
of the constraint is an integer that can be used as an array index.
Note that if this argument takes values in $[0,n]$, the array takes
$O(n)$ space.
\termitem{float}{} \ldots a floating point number.
\termitem{number}{} \ldots a number.
\termitem{natural}{} \ldots a positive integer.
\termitem{any}{} The corresponding argument of every occurrence
of the constraint can have any type. This is the default value.
\end{description}
\begin{description}
\directive{chr_type}{1}{+TypeDeclaration}
User-defined types are algebraic data types, similar to those in Haskell
or the discriminated unions in Mercury. An algebraic data type is
defined using chr_type/1:
\begin{code}
:- chr_type type ---> body.
\end{code}
If the type term is a functor of arity zero (i.e. one having zero
arguments), it names a monomorphic type. Otherwise, it names a
polymorphic type; the arguments of the functor must be distinct type
variables. The body term is defined as a sequence of constructor
definitions separated by semi-colons.
Each constructor definition must be a functor whose arguments (if
any) are types. Discriminated union definitions must be transparent:
all type variables occurring in the body must also occur in the type.
Here are some examples of algebraic data type definitions:
\begin{code}
:- chr_type color ---> red ; blue ; yellow ; green.
:- chr_type tree ---> empty ; leaf(int) ; branch(tree, tree).
:- chr_type list(T) ---> [] ; [T | list(T)].
:- chr_type pair(T1, T2) ---> (T1 - T2).
\end{code}
Each algebraic data type definition introduces a distinct type.
Two algebraic data types that have the same bodies are considered to be
distinct types (name equivalence).
Constructors may be overloaded among different types: there may be any number
of constructors with a given name and arity, so long as they all have different
types.
Aliases can be defined using ==. For example, if your program uses lists
of lists of integers, you can define an alias as follows:
\begin{code}
:- chr_type lli == list(list(int)).
\end{code}
\end{description}
\paragraph{Type Checking}
Currently two complementary forms of type checking are performed:
\begin{enumerate}
\item Static type checking is always performed by the compiler. It is
limited to CHR rule heads and CHR constraint calls in rule bodies.
Two kinds of type error are detected. The first is where a variable
has to belong to two types. For example, in the program:
\begin{code}
:-chr_type foo ---> foo.
:-chr_type bar ---> bar.
:-chr_constraint abc(?foo).
:-chr_constraint def(?bar).
foobar @ abc(X) <=> def(X).
\end{code}
the variable \texttt{X} has to be of both type \texttt{foo} and \texttt{bar}.
This is reported as a type clash error:
\begin{code}
CHR compiler ERROR:
`--> Type clash for variable _ in rule foobar:
expected type foo in body goal def(_, _)
expected type bar in head def(_, _)
\end{code}
The second kind of error is where a functor is used that does not belong
to the declared type. For example in:
\begin{code}
:- chr_type foo ---> foo.
:- chr_type bar ---> bar.
:- chr_constraint abc(?foo).
foo @ abc(bar) <=> true.
\end{code}
\const{bar} appears in the head of the rule where something of
type \const{foo} is expected. This is reported as:
\begin{code}
CHR compiler ERROR:
`--> Invalid functor in head abc(bar) of rule foo:
found `bar',
expected type `foo'!
\end{code}
No runtime overhead is incurred in static type checking.
\item Dynamic type checking checks at runtime, during program execution,
whether the arguments of CHR constraints respect their declared types.
The \predref{when}{2} co-routining library is used to delay dynamic type
checks until variables are instantiated.
The kind of error detected by dynamic type checking is where a functor
is used that does not belong to the declared type. For example, for the program:
\begin{code}
:-chr_type foo ---> foo.
:-chr_constraint abc(?foo).
\end{code}
we get the following error in an erroneous query:
\begin{code}
?- abc(bar).
ERROR: Type error: `foo' expected, found `bar'
(CHR Runtime Type Error)
\end{code}
Dynamic type checking is weaker than static type checking in the sense
that it only checks the particular program execution at hand rather than
all possible executions. It is stronger in the sense that it tracks
types throughout the whole program.
Note that it is enabled only in debug mode, as it incurs some (minor)
runtime overhead.
\end{enumerate}
\subsection{CHR Compilation}
\label{sec:chr-compilation}
%--------------------
The SWI-Prolog CHR compiler exploits term_expansion/2 rules to translate
the constraint handling rules to plain Prolog. These rules are loaded
from the library \pllib{chr}. They are activated if the compiled file
has the \fileext{chr} extension or after finding a declaration in the
following format:
\begin{code}
:- chr_constraint ...
\end{code}
It is advised to define CHR rules in a module file, where the module
declaration is immediately followed by including the library(chr) library
as exemplified below:
\begin{code}
:- module(zebra, [ zebra/0 ]).
:- use_module(library(chr)).
:- chr_constraint ...
\end{code}
Using this style, CHR rules can be defined in ordinary Prolog .pl files and
the operator definitions required by CHR do not leak into modules where they
might cause conflicts.
\section{Debugging CHR programs} \label{sec:chr-debugging}
%=================
The CHR debugging facilities are currently rather limited. Only tracing
is currently available. To use the CHR debugging facilities for a CHR
file it must be compiled for debugging. Generating debug info is
controlled by the CHR option \prologflag{debug}, whose default is derived
from the SWI-Prolog flag \prologflag{generate_debug_info}. Therefore debug
info is provided unless the \cmdlineoption{--no-debug} is used.
\subsection{CHR debug ports} \label{sec:chr-ports}
%===============
For CHR constraints the four standard ports are defined:
\begin{description}
\termitem{call}{}
A new constraint is called and becomes active.
\termitem{exit}{}
An active constraint exits: it has either been inserted in the store after
trying all rules or has been removed from the constraint store.
\termitem{fail}{}
An active constraint fails.
\termitem{redo}{}
An active constraint starts looking for an alternative solution.
\end{description}
In addition to the above ports, CHR constraints have five additional
ports:
\begin{description}
\termitem{wake}{}
A suspended constraint is woken and becomes active.
\termitem{insert}{}
An active constraint has tried all rules and is suspended in
the constraint store.
\termitem{remove}{}
An active or passive constraint is removed from the constraint
store.
\termitem{try}{}
An active constraint tries a rule with possibly
some passive constraints. The try port is entered
just before committing to the rule.
\termitem{apply}{}
An active constraint commits to a rule with possibly
some passive constraints. The apply port is entered
just after committing to the rule.
\end{description}
\subsection{Tracing CHR programs}
\label{sec:chr-tracing}
%=================
Tracing is enabled with the chr_trace/0 predicate
and disabled with the chr_notrace/0 predicate.
When enabled the tracer will step through the \const{call},
\const{exit}, \const{fail}, \const{wake} and \const{apply} ports,
accepting debug commands, and simply write out the other ports.
The following debug commands are currently supported:
\begin{verbatim}
CHR debug options:
<cr> creep c creep
s skip
g ancestors
n nodebug
b break
a abort
f fail
? help h help
\end{verbatim}
Their meaning is:
\begin{description}
\termitem{creep}{}
Step to the next port.
\termitem{skip}{}
Skip to exit port of this call or wake port.
\termitem{ancestors}{}
Print list of ancestor call and wake ports.
\termitem{nodebug}{}
Disable the tracer.
\termitem{break}{}
Enter a recursive Prolog top level. See break/0.
\termitem{abort}{}
Exit to the top level. See abort/0.
\termitem{fail}{}
Insert failure in execution.
\termitem{help}{}
Print the above available debug options.
\end{description}
\subsection{CHR Debugging Predicates} \label{sec:chr-debug-preds}
%====================================
The \pllib{chr} module contains several predicates that allow
inspecting and printing the content of the constraint store.
\begin{description}
\predicate{chr_trace}{0}{}
Activate the CHR tracer. By default the CHR tracer is activated and
deactivated automatically by the Prolog predicates trace/0 and
notrace/0.
\predicate{chr_notrace}{0}{}
Deactivate the CHR tracer. By default the CHR tracer is activated and
deactivated automatically by the Prolog predicates trace/0 and
notrace/0.
\predicate{chr_leash}{1}{+Spec}
Define the set of CHR ports on which the CHR tracer asks for user
intervention (i.e.\ stops). \arg{Spec} is either a list of ports as
defined in \secref{chr-ports} or a predefined `alias'. Defined aliases
are: \const{full} to stop at all ports, \const{none} or \const{off} to
never stop, and \const{default} to stop at the \const{call},
\const{exit}, \const{fail}, \const{wake} and \const{apply} ports.
See also leash/1.
\predicate{chr_show_store}{1}{+Mod}
Prints all suspended constraints of module \arg{Mod} to the standard
output. This predicate is automatically called by the SWI-Prolog top level at
the end of each query for every CHR module currently loaded. The Prolog flag
\const{chr_toplevel_show_store} controls whether the top level shows the
constraint stores. The value \const{true} enables it. Any other value
disables it.
\predicate{find_chr_constraint}{1}{-Constraint}
Returns a constraint in the constraint store. Via backtracking, all constraints
in the store can be enumerated.
\end{description}
\section{CHR Examples} \label{sec:chr-examples}
%================
Here are two example constraint solvers written in CHR.
\begin{itemize}
\item
The program below defines a solver with one constraint,
\nopredref{leq}{2}, which is a less-than-or-equal constraint, also known
as a partial order constraint.
\begin{code}
:- module(leq,[leq/2]).
:- use_module(library(chr)).
:- chr_constraint leq/2.
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).
\end{code}
When the above program is saved in a file and loaded in SWI-Prolog, you can
call the \nopredref{leq}{2} constraints in a query, e.g.:
\begin{code}
?- leq(X,Y), leq(Y,Z).
leq(_G23837, _G23841)
leq(_G23838, _G23841)
leq(_G23837, _G23838)
true .
\end{code}
When the query succeeds, the SWI-Prolog top level prints the content of
the CHR constraint store and displays the bindings generated during the
query. Some of the query variables may have been bound to attributed
variables, as you see in the above example.
\item
The program below implements a simple finite domain
constraint solver.
\begin{code}
:- module(dom,[dom/2]).
:- use_module(library(chr)).
:- chr_constraint dom(?int,+list(int)).
:- chr_type list(T) ---> [] ; [T|list(T)].
dom(X,[]) <=> fail.
dom(X,[Y]) <=> X = Y.
dom(X,L) <=> nonvar(X) | memberchk(X,L).
dom(X,L1), dom(X,L2) <=> intersection(L1,L2,L3), dom(X,L3).
\end{code}
When the above program is saved in a file and loaded in SWI-Prolog, you can
call the \nopredref{dom}{2} constraints in a query, e.g.:
\begin{code}
?- dom(A,[1,2,3]), dom(A,[3,4,5]).
A = 3.
\end{code}
\end{itemize}
\section{CHR compatibility} \label{sec:chr-compatibility}
%==================
\subsection{The Old SICStus CHR implemenation}
\label{sec:chr-sicstus}
There are small differences between the current K.U.Leuven CHR system
in SWI-Prolog, older versions of the same system, and SICStus' CHR system.
The current system maps old syntactic elements onto new ones and ignores a
number of no longer required elements. However, for each a {\em deprecated}
warning is issued. You are strongly urged to replace or remove deprecated
features.
Besides differences in available options and pragmas, the following differences
should be noted:
\begin{itemlist}
\item [The \nopredref{constraints}{1} declaration]
This declaration is deprecated. It has been replaced with the
chr_constraint/1 declaration.
\item [The \nopredref{option}{2} declaration]
This declaration is deprecated. It has been replaced with the
chr_option/2 declaration.
\item [The \nopredref{handler}{1} declaration]
In SICStus every CHR module requires a \nopredref{handler}{1}
declaration declaring a unique handler name. This declaration is valid
syntax in SWI-Prolog, but will have no effect. A warning will be given
during compilation.
\item [The \nopredref{rules}{1} declaration]
In SICStus, for every CHR module it is possible to only enable a subset
of the available rules through the \nopredref{rules}{1} declaration. The
declaration is valid syntax in SWI-Prolog, but has no effect. A
warning is given during compilation.
\item [Guard bindings]
The \texttt{check_guard_bindings} option only turns invalid calls to
unification into failure. In SICStus this option does more: it intercepts
instantiation errors from Prolog built-ins such as is/2 and
turns them into failure. In SWI-Prolog, we do not go this far, as we like
to separate concerns more. The CHR compiler is aware of the CHR code, the Prolog
system, and the programmer should be aware of the appropriate meaning of the
Prolog goals used in guards and bodies of CHR rules.
\end{itemlist}
\subsection{The Old ECLiPSe CHR implemenation}
\label{sec:chr-eclipse}
The old ECLiPSe CHR implementation features a \nopredref{label_with}{1} construct
for labeling variables in CHR constraints. This feature has long since been abandoned.
However, a simple transformation is all that is required to port the functionality.
\begin{code}
label_with Constraint1 if Condition1.
...
label_with ConstraintN if ConditionN.
Constraint1 :- Body1.
...
ConstraintN :- BodyN.
\end{code}
is transformed into
\begin{code}
:- chr_constraint my_labeling/0.
my_labeling \ Constraint1 <=> Condition1 | Body1.
...
my_labeling \ ConstraintN <=> ConditionN | BodyN.
my_labeling <=> true.
\end{code}
Be sure to put this code after all other rules in your program! With \nopredref{my_labeling}{0}
(or another predicate name of your choosing) the labeling is initiated, rather than ECLiPSe's
\nopredref{chr_labeling}{0}.
\section{CHR Programming Tips and Tricks} \label{sec:chr-guidelines}
%==================
In this section we cover several guidelines on how to use CHR to write
constraint solvers and how to do so efficiently.
\begin{itemlist}
\item [Check guard bindings yourself]
It is considered bad practice to write guards that bind variables of
the head and to rely on the system to detect this at runtime. It is
inefficient and obscures the working of the program.
\item [Set semantics]
The CHR system allows the presence of identical constraints, i.e.
multiple constraints with the same functor, arity and arguments. For
most constraint solvers, this is not desirable: it affects efficiency
and possibly termination. Hence appropriate simpagation rules should be
added of the form: \[ constraint \backslash constraint <=> true \]
\item [Multi-headed rules]
Multi-headed rules are executed more efficiently when the constraints
share one or more variables.
\item [Mode and type declarations]
Provide mode and type declarations to get more efficient program execution.
Make sure to disable debug (\cmdlineoption{--no-debug}) and enable
optimization (\cmdlineoption{-O}).
\item [Compile once, run many times]
Does consulting your CHR program take a long time in SWI-Prolog? Probably
it takes the CHR compiler a long time to compile the CHR rules into Prolog
code. When you disable optimizations the CHR compiler will be a lot quicker,
but you may lose performance. Alternatively, you can just use SWI-Prolog's
qcompile/1 to generate a \fileext{qlf} file once from your
\fileext{pl} file. This \fileext{qlf} contains the generated code of the
CHR compiler (be it in a binary format). When you consult the \fileext{qlf}
file, the CHR compiler is not invoked and consultation is much faster.
\item [Finding Constraints]
The \predref{find_chr_constraint}{1} predicate is fairly expensive. Avoid it,
if possible. If you must use it, try to use it with an instantiated top-level
constraint symbol.
\end{itemlist}
\section{CHR Compiler Errors and Warnings} \label{sec:chr-warnings-and-errors}
%==================
In this section we summarize the most important error and warning messages
of the CHR compiler.
\subsection{CHR Compiler Errors}
\label{sec:chr-errors}
\begin{description}
\item[Type clash] for variable ... in rule ...
This error indicates an inconsistency between declared types;
a variable can not belong to two types. See static type
checking.
\item[Invalid functor] in head ... of rule ...
This error indicates an inconsistency between a declared type
and the use of a functor in a rule. See static type checking.
\item[Cyclic alias] definition: ... == ...
You have defined a type alias in terms of itself, either
directly or indirectly.
\item[Ambiguous type aliases]
You have defined two overlapping type aliases.
\item[Multiple definitions] for type
You have defined the same type multiple times.
\item[Non-ground type] in constraint definition: ...
You have declared a non-ground type for a constraint argument.
\item[Could not find type definition] for ...
You have used an undefined type in a type declaration.
\item[Illegal mode/type declaration]
You have used invalid syntax in a constraint declaration.
\item[Constraint multiply defined]
There is more than one declaration for the same constraint.
\item[Undeclared constraint] ... in head of ...
You have used an undeclared constraint in the head of a rule.
This often indicates a misspelled constraint name or wrong
number of arguments.
\item[Invalid pragma] ... in ... Pragma should not be a variable.
You have used a variable as a pragma in a rule. This is not
allowed.
\item[Invalid identifier] ... in pragma passive in ...
You have used an identifier in a passive pragma that
does not correspond to an identifier in the head of the rule.
Likely the identifier name is misspelled.
\item[Unknown pragma] ... in ...
You have used an unknown pragma in a rule. Likely the
pragma is misspelled or not supported.
\item[Something unexpected] happened in the CHR compiler
You have most likely bumped into a bug in the CHR compiler.
Please contact Tom Schrijvers to notify him of this error.
\end{description}
|