Constraint Programming fits well with Prolog as long as you stick to pure logic. But, as you demonstrate, one cannot freely mix procedural elements such as **cut (!)** and **if-then-else (->;)** with the constraint logic.

The use of if-then-else or cuts is only safe if the condition is entailed (i.e. unconditionally true) or disentailed (unconditionally false) at "constraint setup time". In practice that means that such conditions should not contain *problem variables* (domain variables etc), but only *problem parameters* (constants) that are known a priori. Dedicated modelling languages distinguish these two things, but Prolog doesn't.

**How NOT to express alternatives in constraint models**

The above means that you cannot use cut/if-then-else to express the kind of alternative that you wanted to express. It might be tempting to simply get rid of the committed-choice aspect of the conditional, and rewrite as a pure disjunction. For example, you could rewrite

```
( Usage #>= 1000 -> Rate#=7, Bonus#=100 % WRONG
; Rate#=9, Bonus#=0
)
```

as a pure disjunction

```
( Usage #>= 1000, Rate#=7, Bonus#=100 % INEFFICIENT
; Usage #< 1000, Rate#=9, Bonus#=0
)
```

While this is now logically correct, do not do this! Prolog explores alternatives (expressed using semicolon **(;)** or multiple clauses) via backtracking, i.e. by eagerly choosing one alternative first, and going back to the other later. This will normally ruin any hope for an efficient constraint program! In a constraint program, all search should be located in the search/labeling routine.

**Reified constraints**

If both the condition and the branches of the alternatives are constraints that have a reified implementation (i.e. an implementation that can reflect the truth of a constraint in a boolean variable), you are in luck: you can rewrite the whole conditional alternative with the help of the special connectives for reified constraints (in ECLiPSe: `and`

, `or`

, `neg`

, `=>`

, `#=`

). For the above example:

```
Usage #>= 1000 => Rate#=7 and Bonus#=100, % OK
Usage #< 1000 => Rate#=9 and Bonus#=0
```

or

```
Usage #>= 1000 and Rate#=7 and Bonus#=100 or % OK
Usage #< 1000 and Rate#=9 and Bonus#=0
```

Unfortunately, only the basic arithmetic constraints have reified versions and can be combined in this way!

**Using other built-in constraints**

In a way, dealing with alternatives is the most difficult part of problem solving, and many built-in constraints address this. Is is therefore worth checking whether the problem can be modelled on top of existing built-in constraints *without* having any explicit disjunctions in the model. Candidates are
element/3, table/2. disjunctive/2
and many others.

**Delaying the choice**

A last resort solution is to delay the exploration of the alternatives until the truth of the condition can be unambiguously decided. In ECLiPSe this is easiest with delay clauses. Using the OP's example:

```
delay choice(A, B) if var(A);var(B). % wait for A,B to be known
choice(A, B) :-
( (A>3 ; B>3) -> % can now use normal Prolog tests
write("expression 1")
;
write("expression 2")
).
```

This works, but will only act once both A and B are instantiated. If, as in this case, the condition is reifiable, we can do somewhat better:

```
choice(A, B) :-
Bool #= (A#>3 or B#>3),
delayed_choice(Bool).
delay delayed_choice(Bool) if var(Bool).
delayed_choice(1) :- write("expression 1").
delayed_choice(0) :- write("expression 2").
```

This will already act when the condition is satisfied by the domains:

```
?- choice(A, B), B #> 3.
expression 1
```

**Turning general disjunctions into a constraint**

ECLiPSe has a nifty feature called *Generalised Propagation* in
library(propia). This can effectively turn Prolog disjunctions into a constraint, by using a simple annotation. Starting with the correct, but inefficient formulation above, we can write:

```
?- ( Usage #>= 1000, Rate#=7, Bonus#=100
; Usage #< 1000, Rate#=9, Bonus#=0
) infers most.
Usage = Usage{-1.0Inf .. 1.0Inf}
Rate = Rate{[7, 9]}
Bonus = Bonus{[0, 100]}
There is 1 delayed goal.
Yes (0.00s cpu)
```

As the domains of `Rate`

and `Bonus`

show, useful information has been extracted from the disjunction, even before the applicable alternative can be decided.

`->`

do not flock together directly. Consider to use`if_/3`

.