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 that can only be assigned an even number:
?- freeze(X, X mod 2 =:= 0), X = 3 No
- 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. Usefrozen(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),or,(Cond1, Cond2). See also freeze/2 and dif/2. The implementation can deal with cyclic terms in X and Y.;(Cond1, Cond2)The when/2 predicate is realised using attributed variables associated with the module
when. It is defined in the autoload librarylibrary(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 variables associated with the module
dif. It is defined in the autoload librarylibrary(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 contradicting 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 attribute variables or whose attributes
are modified104Tracking
modifications is currently not complete and this feature may be dropped
completely in future versions. by Goal,
regardless of whether or not 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.