[net.lang.prolog] Adding an Algorithmic Capability to Prolog

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

From:  Abbott at AEROSPACE (Russ Abbott)

I'd like to suggest a notion that many readers of this Digest
may consider heresy, namely that Prolog is not the ultimate
programming language.  And I'd like to open a discussion on
the following subject (if I'm not stoned for making the
suggestion):  How can an algorithmic capability be included
cleanly in Prolog ?

As prolog (pardon) let me say that I've been very impressed
with the way that Prolog *is* able to accommodate certain
programming paradigms:

     - concurrency (in certain senses), types (in certain
       senses),
     - object-oriented-ness (in certain senses), etc.  I see
       Prolog as in the process of developing a programming
       style that suits its capabilities.  I'm excited and
       pleased with the process.  I expect that this process
       will probably go on for several years while Prolog
       either annexes or rejects various modern programming
       notions.

My problem is more fundamental.  Prolog is not an algorithmic
language: that is supposed to be one its strengths.  Yet in
programming computers it seems that one cannot avoid algorithms
--in the sense of step-by-step sequences of actions that one
wants to have occur.  Even Prolog programs include algorithms.
I challenge any Prolog programmer to claim that he has never
written an algoritm in Prolog.  Currently one writes algorithms
in Prolog by making use of the algorithm by which Prolog itself
attempts to satisfy goals.  By riding on the coat tails of that
algorithms one can compute anything computable.  But doing so
often obscures what one wants rather than clarifies it.

Algorithms appear most often in those Prolog program that include
Prolog predicates with side effects, I.e., the "impurities" in
Prolog, such as read, write, assert, etc.  I claim that we will
never get rid of these impurities.  It seems to me that, like
it or not:

     (1) any program that is to be of much use in the world has
         to have I/O, and

     (2) any program that is not simply a function (and very few
         programs of any real use are) has to have a way of changing
         its behavior on the basis of past inputs.  That is,
         programs must have a "database" capability of some sort,
         and that means assert or the equivalent.

Another argument for adding an algorithmic capability may be
built on the nature of Prolog as a "passive" language.  In
"pure" Prolog one cannot define a "process," I.e., something
that continues to operate in time.  At its heart Prolog lets
one create a static body of information that may be queried.
It does not provide means to define an ongoing process that
continues in operation indefinitely, doing whatever it is
supposed to do. Yet many programs do have that form.

The Prolog interpreter itself is of this form.  Once started,
it's an ongoing process that is always interacting with the
user at the terminal. It makes no (predicate-logical) sense
to write the top level of the Prolog interpreter as a Prolog
predicate.  Even if one could make the following work as an
interactive program (E.g., by making Input and Output special
variable names, for example), I'm not happy with:

        interpret([Input | Inputs], [Output | Outputs]) :-
                process(Input, Output),
                interpret(Inputs, Outputs).

Since asserts performed for one input may affect how later inputs
are processed, this forces asserts in the middle of interpret to
affect the same call to interpret--since there is only one call
to interpret.  More generally, it imples (incorrectly) that all
the inputs exist at once.  It ignores the element of time completely.
Why should one have to live with this fiction ?

Nor am I happy with the other approach:

        interpret :-
                read(Term),
                process(Term),
                interpret.
or
        interpret :-
                repeat,
                read(Term),
                process(Term),     % process has a cut at the end.
                fail.

These are both the "coat tail" approach, using Prolog's underlying
satisfaction algorithm for a purpose for which it wasn't "intended."
In addition the first version stacks wasted return pointers for no
good reason. (I know that tail recursion can be optimized away, but
that isn't the point.) The second is even worse conceptually; it has
little if anything to do with Prolog as a logic language.  Both of
these also suffer from the problem mentioned above--asserts within
a call to interpret affect later processing of the same call (since
there is only one call to interpret).

The problem may be summarized: predicate calculus is a language of
static facts; algorithms express sequences of operations in time.
Prolog implements predicate calculus; most useful programs operate
in time.

So given all that what am I asking ?  I'm suggesting that Prolog
needs to be wedded cleanly to some way to express algorithms--rather
than to continue to use the coat tail approach to writing algorithms
in Prolog.  I'd like to open a discussion on how best to do that.

I think that a side benefit of such a successful wedding will be
that most, if not all, of the "impurities" in current Prolog can
be moved to the algorithm side--where they will not be impurities.
The extended Prolog will thus be both cleaner and more useful.

I am now heading for my bomb shelter to await replies.

-- Russ Abbott