[net.lang.prolog] Purity, Again

Abbott%AEROSPACE@sri-unix.UUCP (11/10/83)

From:  Abbott at AEROSPACE (Russ Abbott)

I agree with Richard that

(1)
     f_i(X1, X2, .. , Xn) =.. [f_i, X1, X2, .. , Xn].

     call(p_i(X1, X2, .. , Xn) :- p_i(X1, X2, .. , Xn).

(and let's include)

     current_predicate(p, p(X1, X2, .. , Xn)).   % Succeeds if p/n
                                                 %  is defined.


are first order definitions of  =.. (univ),  call, and
current_predicate for particular f_i and p_i.  One could have as
many of these as one wants. (Note,  current_predicate  is defined
in the Edinburgh C-Prolog that I have.  I'm assuming that it's a
more or less standard built-in.)

But I don't suppose one would really want to claim that

(2) (for all n)

        F(X1, X2, .. , Xn) =.. [F, X1, X2, .. , Xn].

        call(P(X1, X2, .. , Xn)) :-
                current_predicate(P, P(X1, X2, .. , Xn)),
                P(X1, X2, .. , Xn)).

        current_predicate(P, P(X1, X2, .. , Xn)).

are also first order definitions ?  I suppose the real question is:
when is there a difference between (1) and (2)?  As Richard points
out (that David Warren points out), for a static collection of
predicates and functors, (2) can be understood as an abbreviation
for (1).  But as Richard also points out, if one allows  assert,
(2) gives one more than (1).  For example,

        assert(new_p(a)),
        call(new_p(a))

will succeed with (2) but not with (1).  It will not succeed with
(1) since under (1) the clause:

        call(new_p(X1, X2, .. , Xn) :- new_p(X1, X2, .. , Xn).

does not exist.

Given all that, and also given that, in fact, Prolog's are built
with  assert and with the (2) version of the functions discussed,
my next question is:  Why don't most Prolog's allow

        call(P(X1, X2, .. , Xn)).

for variable P, where call is defined as above?  It certainly would
be a convenience for the user in certain situations.  According to
the preceding argument it is essentially the same as allowing
assert--which they do.  And in any event, if the system doesn't do
it for me, I can define my own. (Although the syntax isn't quite
so pretty.)

        my_call(P, X) :-
           current_predicate(P, Y),
           not P = my_call,             % to avoid an infinite loop.
           Y,
           Y =.. [P | X].

If P and X are initially uninstantiated,   my_call(P, X)   will
succeed with P instantiated in turn to all the predicates that
succeed with some argument(s), and with X instantiated to the
successful argument list(s).

-- Russ Abbott