The basic facility for output in CLP( ) is the system predicate dump/1, mentioned above, whose argument is a list of target variables. Note that, to use this predicate, the target variables must appear explicitly in the argument (as in dump([A, B])) and not be passed in (as in X = [A, B], dump(X)). This is because the names of the target variables are actually used in the output. The ordering of variables in the list is used to specify a priority on the variables with the later variables having a higher priority. Since dump outputs constraints, there are many equivalent forms of the same set of constraints and the priority ordering is used to express higher priority variables in terms of the lower ones. This gives one form of control over the output from dump. For example, the goal
?- X = 2 * Y + 4, dump([X, Y])
gives Y = 0.5 * X - 2
whereas the reverse order would give back the original constraint.
The predicate dump/2 is a refinement of dump/1, and is designed to be far more flexible. Its first argument is, as before, a list of target variables. Its second argument is a list of constants to be used in place of the original target variables in the output. For example,
?- Names = [a, b], Targets = [X, Y], X > Y, dump(Targets, Names).
results in the output a > b. This predicate is useful when the names of target variables are known only at runtime. More precisely, the operation of dump/2 is as follows: let the first and second arguments be the lists and , where the and are arbitrary terms. Construct new variables , and add to the current collection of constraints the equations . Now obtain a projection of the augmented constraints w.r.t. . Finally, output this projection renaming each target variable by its new name .
In meta-programming it can be useful to obtain the coded form of the constraints with respect to given target variables. This facility is provided by the system predicate dump/3. There are three arguments because it is not sufficient to simply provide the variables to be projected upon (1st argument) and the variable that receives the coded form (3rd argument). The 2nd argument is a list of terms that are to replace the original variables in the coded form, and hence the lengths of the two lists must be the same. For example,
?- NewVars = [A, B, C], Targets = [X, Y, Z], X > Y + Z,
dump(Targets, NewVars, Answer).
results in the binding Answer = [ A B C < 0].
There are two reasons for having such a second argument. First, it is very inconvenient to manipulate a coded form containing variables that have the original arithmetic constraints still imposed on them -- in particular, printing such a term leads to highly counter-intuitive results. Second, in many cases it is more convenient to manipulate ground representations of the coded forms. That is, with syntactic constants replacing the variables. The terms resulting from manipulation can then have the original (or other) variables substituted into place easily.
We conclude with a larger example. We will assume that the predicate p/2 sets up a constraint such that the first argument is a (polynomial) function of the second, and that diff/2 implements symbolic differentiation on coded forms of arithmetic constraints. Then, to find the turning point of the functional relationship established by p/2, we can use the following goal:
solve(DYDX,X) :- eval(DYDX) = 0.
p(Y, X) :-
T = X + 1,
Y = T * T.
?- p(Y, X),
% collect a function Y(X)
dump([Y, X], [V, U], Z),
% get coded form of Y(X)
Z = [C], C =.. ['=', V, RHS],
% assume Z of the form [V = f(U)]
diff(RHS, DVDU),
% symbolic differentiation
solve(DVDU, U),
% find extremum
printf("Turning point: X = %, Y = % n", [U, V]).