Next we consider how these basic facilities may be used for reasoning about programs (see also Section 4.8 which describes how to use the dynamic code facilities). The canonical application for such reasoning is the meta-circular interpreter, discussed in detail in [7]. Like the clause/2 predicate of Prolog, we require a system predicate rule/2 such that the goal ?- rule(H, B) behaves as if there were facts rule(E, F) for each rule E :- F in the program (and of course rule(A, true) for each fact A).
There is, however, one aspect of rule which has no analog in clause: arithmetic function symbols will become coded. More precisely, the system predicate rule behaves as if there were facts rule(quote(E), quote(F)) for each rule E :- F in the rulebase (and rule(quote(A), true) for each fact A). We note that a direct analog to clause can be written in terms of rule:
analog_to_clause(H, B) :-
functor(H, Name, Arity),
functor(H1, Name, Arity), % rule needs a constructed head
eval(H) = eval(H1),
rule(H1, eval(B)).
In a similar fashion, the CLP( ) system predicate retract/1 is like that in PROLOG but differs in that one matches arithmetic function symbols with their coded forms. As before, a direct analog to the PROLOG's retract can be written as follows:
analog_to_retract(eval(R)) :-
functor(R, Name, Arity),
functor(R1, Name, Arity), % retract needs a constructed argument
eval(R) = eval(R1),
retract(R1).
Now consider the following example program:
(a) p(1, 1.5).
(b) p(X, Y) :- Y = 2 * X.
(c) p(X, 2 * X).
(d) p(X, 2 + X).
The goal ?- retract(quote(p(X, 2*X))) removes only the rule (c). The goal
?- analog_to_retract(p(X, 2*X))
on the other hand, should remove rules (c) and (d).
As explained in [7], assert/1 in CLP( )\ differs from that in PROLOG not just because of term codings; additional constraints may have to be added to the asserted rule. For example,
?- X + Y > 2, assert(p(X, Y)).
results in the rule
p(X, Y) :- X + Y > 2.
As another example, the goal:
?- X + Y = 2, X >= 0, Y - 2*X <= 2, X > W, Y - X >= 1,
assert(p(X, Y)).
asserts the rule:
p(X, Y) :- Y = -X + 2, X <= 0.5, -X <= 0.
Note that a considerable simplification of the initial constraints has occurred. More generally, this supports a technique of constraint partial evaluation. This technique consists of executing a query, and then using the simplified form of the answer constraints to construct new rules. These new rules represent a specialization of the program with respect to that query. For example:
resistor(V, I, R) :- V = I * R.
?- resistor(V, I1, R1), resistor(V, I2, R2),
I = I1 + I2,
assert( parallel_resistors(V, I, R1, R2)).
results in the assertion of a rule describing the equivalent voltage-current relationship of a pair of resistors connected in parallel:
parallel_resistors(V, I, R1, R2) :-
V = I2 * R2,
V = (I - I2) * R1.
The facilities we have discussed for adding rules to the database have provided no control over the exact syntax of the rule added. For example constraints may be simplified and/or rearranged before the rule is added. It is particularly important in some applications to have complete control over the syntax of rules added to the database. This control is provided by using a coded form of the rule to be asserted, where assert of a coded rule is defined to add the rule that is coded. For example, the goal
?- assert(quote( p(X, X + X) :- X - 3 > 0 )).
asserts the rule
p(X, X + X) :- X - 3 > 0.
In contrast, the goal
?- assert(p(X, X + X) :- X - 3 > 0).
could, for example, add the (semantically equivalent) rule:
p(X, Y) :- Y = 2*X, Z = X - 3, Z > 0.