Yes, that might be a problem, but don’t think it is. So far, my investigations have shown, at least to my own satisfaction, that it’s remarkably easy and feels very natural to extend Prolog with features from Erlang, or, if you want, to combine the logic programming model of computation with the actor programming model.
Here’s an example from the manuscript which didn’t fit in the Erlang’19 paper. It shows how a tiny yet fairly generic encapsulated search predicate can be implemented on top of an actor in Web Prolog. It doesn’t have all the features a “real” pengine has, but it shows, quite nicely I think, how easy it is to build such a thing on top of an actor:
search(Query, Pid, Options) :-
self(Self),
spawn(query(Query, Self), Pid, [
monitor(true),
src_predicates([query/2])
| Options
]).
query(Query, Parent) :-
self(Self),
call_cleanup(Query, Det=true),
( var(Det)
-> Parent ! success(Self, Query, true),
receive({
next -> fail;
stop ->
Parent ! stopped(Self)
})
; Parent ! success(Self, Query, false)
).
We don’t have to assume that the implementation is available at the remote node. Instead, by passing the src_predicate
option, we send the predicate query/2
along for injection into the workspace of the process. Here is an example of how search/3
can be used to query a remote node:
?- search(p(X), Pid, [
node('http://remote.org')
]).
Pid = 1879876@'http://remote.org'.
?- flush.
Shell got success(1879876@'http://remote.org', p(a), true)
true.
?- $Pid ! next.
true.
?- flush.
Shell got success(1879876@'http://remote.org', p(b), true)
true.
?- $Pid ! stop.
true.
?- flush.
Shell got stopped(1879876@'http://remote.org')
Shell got down(1879876@'http://remote.org', true)
true.
?-
Note that the code for search/3
does not say anything about what should happen if an exception is thrown, which would for example be the case if the predicate called by the goal is not defined. But since the spawned process is monitored, the error message will eventually reach the mailbox of the spawning process anyway, in the form of a down
message. The same is true for failure.
The key here is the receive/1-2
predicate and the decision to make it semidet, allowing it too fail if the body of one of its receive clauses fails. Here’s what I say about the much smaller examples in the paper:
The tiny examples in this section highlighted a vital feature of the Web Prolog design as they showed how Prolog-style search and Erlang-style concurrency can be integrated and how a non-deterministic query can be supplied with a deterministic interface. This is precisely the point where the logic programming model and the actor programming model – represented here by Prolog and Erlang – interface with each other. This suggests that Prolog’s backtracking mechanism is perfectly compatible with, and in fact complements, the proposed Erlang-like mechanisms for spawning actors and handling the communication between them.
Of course, since pengines are available, you don’t have write your own solver.
So, does Web Prolog deserve to be called a multi-paradigm programming language then? Yes, why not, because in the very nicely organised and very well argued taxonomy of programming paradigms by Peter van Roy, as seen below, it is indeed possible to pinpoint exactly where Web Prolog fits in. I have enclosed the relevant boxes in boxes with rounded corners. (The original diagram, with explanations, is available here, and a book chapter, with even more explanations here.)
With access to predicates for asserting and retracting facts in the dynamic database, traditional Prolog has always been able to support imperative programming (and later additions such as setarg/3
has of course amplified this). Thus Prolog has never really been a single-paradigm programming language, and this is reflected in van Roy’s taxonomy. With the addition of support for the actor programming model, Web Prolog becomes a much clearer as well as (in my view) a more interesting example of a multi-paradigm programming language.