next up previous contents index
Next: rule/2retract/1 and assert/1 Up: Meta-programming Previous: Meta-programming

quote/1 and eval/1

   

First we introduce the macro-like operator quote/1 . This is expanded in an outer-most first fashion when expressions are first read. The argument of the quote operator is translated to a version in which all arithmetic operators are translated to a special coded form, which is not otherwise directly accessible to the programmer. This coded form can then be treated like a functor term. In this discussion, such coded forms of arithmetic function symbols will be be represented with a caret over them. For example, the rule


p(X, Y, quote(X + Y)).

would be read in as


p(X, Y, X tex2html_wrap_inline4220 Y).

and so on. Furthermore, the quote operator passes through all other function symbols, constants, variables etc. without changing them. Thus for example, the rule


q(X,Y) :- X = quote(f(g(Y), 2 * Y)).

becomes


q(X,Y) :- X = f(g(Y), 2 tex2html_wrap_inline4222 Y).

Of course, the original form of the rule is always shown when listing the database, etc., but when printing a term, coded function symbols are printed preceded by a caretgif. For example, the query ?- q(X, 5). to the above rule would yield the answer X = f(g(5), 2 ^* 5). Note that that the caret form of coded terms cannot be input directly, but only through the use of quote. Additionally, to facilitate manipulating programs which themselves use meta-programming facilities, we need coded forms of the quote operator itself, as well as the new eval interpreted function symbol, which will be described below. This is why quote is expanded outer-most first. For example,


P = quote(p(quote(X + Y), X + Y)) expands to

P = p( tex2html_wrap_inline4224 (X tex2html_wrap_inline4220 Y), X tex2html_wrap_inline4220 Y)).

Thus an occurrence of quote that appears within the scope of another quote will be translated to tex2html_wrap_inline4224 , and will not be quote-expanded. The eval interpreted function can be coded by using quote as well, for example,


X = quote(eval(1 + 2)) gives

X = tex2html_wrap_inline4232 (1 tex2html_wrap_inline4220 2).

Now, the major linguistic feature for meta-programming with constraints is the interpreted function symbol eval  which converts a coded term to the term it codes. It passes through uninterpreted function symbols, other than those that are coded forms of interpreted ones, without changing them. Likewise for constants and interpreted function symbols. Some examples:


X = 1 tex2html_wrap_inline4220 2, U = eval(X) implies

U = 3.

X = Y tex2html_wrap_inline4220 Z, U = eval(X) implies

U = eval(Y) + eval(Z).

X = Y tex2html_wrap_inline4220 Z, U = eval(X), Y = 1, Z = 2 implies

U = 3.

The function eval has no effect on uninterpreted functors. For example, the goal


?- X = f(a, g(c)), U = eval(X).

results in both U and X being f(a, g(c)). However,


?- X = f(Y, g(c)), U = eval(X).

results in U being f(eval(Y), g(c)), as the ``best'' representation of terms containing eval is that with eval pushed inwards as far as possible.

Formally, the meaning of quote and eval are given by the axioms:   

tex2html_wrap_inline4242

where f ranges over all arithmetic function symbols, g ranges over all uncoded function symbols different from eval, and t, tex2html_wrap_inline4250 range over terms.

In general, deciding the satisfiability of constraints involving quote and eval is a nontrivial problem. Consider for example the two equations:

displaymath4218

The first of these constraints is solvable, while the second is not. There is in fact an algorithm to deal with such constraints in their full generality. However, for efficiency reasons, CLP( tex2html_wrap_inline4020 ) implements a partial algorithm: maintaining constraints so that eval appears only in the form X = eval(Y), these equations are delayed until the argument of eval is constructed. In fact, the delay of such eval equations is implemented in much the same way as nonlinear equations.

For example, consider the goal


?- X = quote(U + 1), eval(X) = 5, Y = eval(U) - 5.

After the first constraint, X is equal to U tex2html_wrap_inline4220 1, but after the second constraint, eval goes as far through X as it can, so we obtain the simplified constraint eval(U) + 1 = 5, which is further simplified to eval(U) = 4. Hence the third constraint results in Y being -1.

However, if the goal were permuted to


?- eval(X) = 5, Y = eval(U) - 5, X = quote(U + 1).

the first and second constraints both result in delayed eval constraints. The third constraint wakes the first delayed eval since X is now constructed, resulting in the constraint eval(U) + 1 = 5 again, which, together with the second delayed eval constraint -- which is not awakened -- results in Y being grounded to -1 again.

As a final example, consider the goal


?- eval(X) + eval(Y) = 4, eval(X) - eval(Y) = 1.

which is rather silly in isolation, but could arise as the result of a longer computation. In this case, the answer constraints are eval(X) = 2.5, eval(Y) = 1.5 although the values of X and Y cannot be determined uniquely. For example, X might be 2.5, or 1 tex2html_wrap_inline4220 1.5, etc. It should be noted that the eval mechanism described here is an approximation to that proposed in [7].


next up previous contents index
Next: rule/2retract/1 and assert/1 Up: Meta-programming Previous: Meta-programming

Alan Borning
Fri Oct 8 12:51:18 PDT 1999