6.2 Coroutining

Coroutining deals with having Prolog goals scheduled for execution as soon as some conditions are fulfilled. In Prolog the most commonly used condition is the instantiation (binding) of a variable. Scheduling a goal to execute immediately after a variable is bound can be used to avoid instantiation errors for some built-in predicates (e.g. arithmetic), do work lazy, prevent the binding of a variable to a particular value, etc. Using freeze/2 for example we can define a variable can only be assigned an even number:

?- freeze(X, X mod 2 =:= 0), X = 3

freeze(+Var, :Goal)
Delay the execution of Goal until Var is bound (i.e. is not a variable or attributed variable). If Var is bound on entry freeze/2 is equivalent to call/1. The freeze/2 predicate is realised using an attributed variable associated with the module freeze. Use frozen(Var, Goal) to find out whether and which goals are delayed on Var.
frozen(@Var, -Goal)
Unify Goal with the goal or conjunction of goals delayed on Var. If no goals are frozen on Var, Goal is unified to true.
when(@Condition, :Goal)
Execute Goal when Condition becomes true. Condition is one of ?=(X, Y), nonvar(X), ground(X), ,(Cond1, Cond2) or ;(Cond1, Cond2). See also freeze/2 and dif/2. The implementation can deal with cyclic terms in X and Y.

The when/2 predicate is realised using attributed variable associated with the module when. It is defined in the autoload library library(when).

dif(@A, @B)
The dif/2 predicate provides a constraint stating that A and B are different terms. If A and B can never unify dif/2 succeeds deterministically. If A and B are identical it fails immediately and finally, if A and B can unify, goals are delayed that prevent A and B to become equal. The dif/2 predicate behaves as if defined by dif(X, Y) :- when(?=(X, Y), X \== Y). See also ?=/2. The implementation can deal with cyclic terms.

The dif/2 predicate is realised using attributed variable associated with the module dif. It is defined in the autoload library library(dif).

call_residue_vars(:Goal, -Vars)
Find residual attributed variables left by Goal. This predicate is intended for debugging programs using coroutining or constraints. Consider a program that poses contracting constraints on a variable. Such programs should fail, but sometimes succeed because the constraint solver is too weak to detect the contradiction. Ideally, delayed goals and constraints are all executed at the end of the computation. The meta predicate call_residue_vars/2 finds variables that are given attributes variables or whose attributes are modified73Tracking modifications is currently not complete and this feature may be dropped completely in future versions. by Goal, regardless or not whether these variables are reachable from the arguments of Goal.

The predicate has considerable implications. During the execution of Goal, the garbage collector does not reclaim attributed variables. This causes some degradation of GC performance. In a well-behaved program there are no such variables, so the space impact is generally minimal. The actual collection of Vars is implemented using a scan of the trail- and global stacks.