Are HiLog terms still useful in modern Prolog?
Within XSB, Hilog terms are very strongly connected to the module system which is unique to XSB. XSB has a functor based module system. That is, within the same scope length(X)
might belong to one module, whereas length(L, N)
might belong to another. As a consequence, call(length(L), N)
might refer to one module and call(length(L, N))
to another:
[Patch date: 2013/02/20 06:17:59]
| ?- use_module(basics,length/2).
yes
| ?- length(Xs,2).
Xs = [_h201,_h203]
yes
| ?- call(length(Xs),2).
Xs = [_h217,_h219]
yes
| ?- use_module(inex,length/1).
yes
| ?- length(Xs,2).
Xs = [_h201,_h203]
yes
| ?- call(length(Xs),2).
++Error[XSB/Runtime/P]: [Existence (No module inex exists)] in arg 1 of predicate load
| ?- call(call(length,Xs),2).
Xs = [_h228,_h230];
It might be that in such a context there are differences between call/N
and Hilog terms. I have, however, so far not found one.
Historically, Hilog terms have been introduced 1987-1989. At that point in time, call/N
already existed as built-ins in NU and as library(call)
in Quintus Prolog with only cursory documentation. It has been proposed 1984 by Richard O'Keefe. On the other hand, call/N
was clearly unknown to the authors of Hilog, as is exemplified on p.1101 of Weidong Chen, Michael Kifer, David Scott Warren: HiLog: A First-Order
Semantics for Higher-Order Logic Programming Constructs. NACLP
1989. 1090-1114. MIT-Press.
... Generic transitive closure can also be defined in Prolog:
closure(R, X, Y) :- C =.. [R, X, Y], call(C). closure(R, X, Y) :- C =.. [R, X, Z], call(C), closure(R, Z, Y).
However, this is obviously inelegant compared to HiLog (see Section 2.1), since this involves both constructing a term out of a list and reflecting this term into an atomic formula using "call". The point of this example is that the lack of theoretical foundations for higher-order constructs in Prolog resulted in an obscure syntax, which partially explains why Prolog programs involving such constructs are notoriously hard to understand.
Now, this can be done with call/N
like so:
closure(R, X, Y) :- call(R, X, Y).
closure(R, X, Y) :- call(R, X, Z), closure(R, Z, Y).
Which is even more general than the (=..)/2
-version because R
is no longer restricted to being an atom. As an aside, I'd rather prefer to write:
closure(R_2, X0,X) :- call(R_2, X0,X1), closure0(R_2, X1,X).
closure0(_R_2, X,X).
closure0(R_2, X0,X) :- call(R_2, X0,X1), closure0(R_2, X1,X).