While delay-clauses are an elegant, declarative way of specifying how a program should execute, it is sometimes necessary to be more explicit about suspension and waking conditions. The built-in predicate suspend/3 is provided for this purpose2. It allows one to explicitly create a suspended goal, specify its priority and its exact waking conditions.
suspend(Goal, Prio, CondList)
is called, Goal will be suspended with priority Prio and it will wake up as soon as one of the conditions specified in the CondList is satisfied. This list contains specifications of the form
Vars -> Cond
to denote that as soon as one of the variables in the term Vars satisfies the condition Cond, the suspended goal will be woken and then executed as soon as the program priority allows it. CondList can also be a single specification.
The condition Cond can be the name of a system-defined waking condition, e.g.,
means that as soon as one (or both) of the variables X, Y is instantiated, the suspended goal will be woken. These variables are also called the suspending variables of the goal.
Cond can also be the specification of a suspension list defined in one of currently loaded library attributes. For example, when the interval solver library lib(ic) is loaded, either of
[A,B]->ic:min [A,B]->ic:(min of ic)
triggers the suspended goal as soon as the minimum element of the domain of either A or B are updated (see Constraint Library Manual, IC Library).
Another admissible form of condition Cond is
which suspends the goal on the global trigger condition Name (see section 18.7.3).
Using suspend/3, we can rewrite our first delay-clause example from above as follows:
report_binding(X) :- ( var(X) -> suspend(report_binding(X), 0, X->inst) ; printf("Variable has been bound to %w\n", [X]) ).
Here, when the predicate is called with an uninstantiated argument, we explicitly suspend a goal with the condition that it be woken as soon as X becomes instantiated. The priority is given as 0, which indicates the default priority (0 is not a valid priority itself). Running this code produces the following:
?- report_binding(X). X = X There is 1 delayed goal. Yes (0.00s cpu)
When X is later instantiated, it will wake up and print the message:
?- report_binding(X), writeln(here), X = 99. here Variable has been bound to 99 X = 99 Yes (0.00s cpu)