Search code examples
moduleprologiso-prologmeta-predicatexsb

Are HiLog terms still useful in modern Prolog?


Are Hilog terms (i.e. compounds having as functors arbitrary terms) still regarded as a powerful feature in XSB Prolog (or any other Prolog) ? Are there many XSB projects currently using this feature ? which of them for example ?

I ask since as far as I understand higher order programming is equally possible using the ISO built-in call/N.

Specifically, I would like to understand if XSB is using Hilog terms just for historical reasons or if Hilog terms have considerable advantages in comparison to the current ISO standard.


Solution

  • 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).