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.
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).
HiLog allows goals such as
foo(X(a, Y(b))).
and ISO Prolog does not. In ISO Prolog, you'd have to write
foo(T), T=..[X, a, R], R=..[Y, b].
which is less convenient and might be slower.
Related
Negation as failure is usually considered impure. The Prolog interpreter needed for negation as failure must realize SLDNF which is an extension of SLD.
The predicate (\=)/2 is for example used in the library(reif). It can be bootstrapped via negation as failure as follows, but is often a built-in:
X \= Y :- \+ X = Y.
Would it be possible to implement (\=)/2 as a pure predicate? Using only pure Prolog, i.e. only first order horn clauses?
Would it be possible to implement (=)/2 as a pure predicate? Using only pure Prolog, i.e. only first order horn clauses?
You can't implement (\=)/2 in pure Prolog.
Proof:
In logic, conjunction is commutative, and pure Prolog queries, if they terminate, must be logical.
However, with (\=)/2, the order of the terms matters, so it is not logical:
?- X \= Y, X=0, Y=1.
false.
?- X=0, Y=1, X \= Y.
X = 0,
Y = 1.
I want a predicate to tell whether a particular atom (say x) appears inside a compound term, however deeply nested.
I tried to read about predicates given at https://www.swi-prolog.org/pldoc/man?section=manipterm. I think it will involve walking down the compound term using functor/3 and ../2 recusively. Is there a simpler approach, or some library that does this?
Carlo's elegant answer works on SWI-Prolog but is not portable as the ISO Prolog standard specification for the arg/3 predicate (which most Prolog systems implement) requires its first argument to be bound to an integer, preventing using it as a backtracable generator of compound term arguments. A more portable alternative would be:
haystack_needle(H, N) :-
H == N.
haystack_needle(H, N) :-
functor(H, _, A),
between(1, A, I),
arg(I, H, A),
haystack_needle(A, N).
The between/3 predicate is not specified in the ISO Prolog standard but it's a de facto standard predicate usually provided as either a built-in predicate or a library predicate.
Ignoring cyclic terms, I would use ==/2,compound/1 and arg/3
haystack_needle(H,N) :- H==N.
haystack_needle(H,N) :- compound(H),arg(_,H,A),haystack_needle(A,N).
haystack_needle/2 will succeed multiple times, then will allow for counting occurrences:
?- aggregate(count, haystack_needle(t(a,x,b,[x,x,x]),x), C).
C = 4.
Note, the needle does not need to be an atom...
You can use once/1 to tell if needle appears in haystack:
?- once(haystack_needle(t(a,x,b,[x,x,x]),x)).
true.
?- once(haystack_needle(t(a,x,b,[x,x,x]),z)).
false.
As noted by Paulo, arg/3 could not act appropriately in ISO compliant Prologs.
A portable alternative (with arguments swapped without other purpose than avoiding confusion) could be
needle_haystack(N,H) :- N==H.
needle_haystack(N,H) :- H=..[_|As],member(A,As),needle_haystack(N,A).
Of course, if member/2 is available :)
There is a lot of hype around the dif/2 constraint, especially as a rescue for some non-declarativity of (\=)/2 and (\==)/2. This non-declarativity is often characterized as non-monotonicity and examples of non-communtativity are given.
But what would be the means to test whether test cases involving dif/2 are commutative. Here is a meta explanation what I want to do:
I make a commutativity test, and I want to probe that both variants
give the same result:
?- A, B.
-- versus --
?- B, A.
So usually you can check monotonicity, if it boils down to checking commutativity, with the (==)/2 built-in predicate. Since this predicate follows instantiated variables.
But if you are testing cases that produce constraints, call_with_residue/2
is not enough, you need also to have equality of constraints. Which can
be tricky, as the following example shows:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.23)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam
?- dif(f(X,X),f(a(U,g(T)),a(g(Z),U))), X=a(g(Z),U).
X = a(g(Z), U),
dif(f(a(g(Z), U), U, Z, U, T), f(a(U, g(T)), g(Z), T, g(Z), Z)).
?- X=a(g(Z),U), dif(f(X,X),f(a(U,g(T)),a(g(Z),U))).
X = a(g(Z), U),
dif(f(U, T), f(g(Z), Z)).
Any ideas how to proceed?
Disclaimer, its a trap:
I don't endorse commutativity testing as a good testing method, where you can separate good and bad predicates versus a specification. Since usually both the good and bad predicates might have no problems with commutativity.
I am using commutativity testing as a vehicle to find out about methods for equality of dif/2 constraints. This equality can then be used in more traditional test cases as a validation point.
There are several ways. Maybe the easiest in this case is to simply re-post the collected residual constraints.
In this example, we get:
?- X = a(g(Z), U),
dif(f(a(g(Z), U), U, Z, U, T), f(a(U, g(T)), g(Z), T, g(Z), Z)).
X = a(g(Z), U),
dif(f(U, T), f(g(Z), Z)).
The goal is now much simpler!
You can collect residual goals with copy_term/3 and call_residue_vars/2.
I am looking resources for learning resolving of constraints in Prolog. For example,
List=[X, Y, Z], List ins 1..4, X - Y #= Z.
What I understand, your want to get concrete solutions (and not the domains). For this, use label/1 or labeling/2, which will give all the explicit solutions (via backtracking). In SWI-Prolog, these predicates are documented here: labeling/2 .
label(List) is equivalent to labeling([],List).
For this simple example, label(List) would suffice:
?- List=[X, Y, Z], List ins 1..4, X - Y #= Z,label(List).
In general, you would benefit by reading the full documentation of clpfd (here for SWI-Prolog).
How can I express next 3 sentences in Prolog?
All summers are warm. If it not summer, then it is winter. Now it is winter.
Nice question.
As #larsman (well, #FredFoo now, I think) rightly said, can be a large thema. And his answer is very good indeed.
As your question could be driven by necessity of a custom language (one of main Prolog' uses), here I propose the syntax sugar for a dummy DSL (what that's means it's totally empty now...)
:- op(500, fx, all).
:- op(500, fx, now).
:- op(600, xfx, are).
:- op(700, fx, if).
:- op(399, fx, it).
:- op(398, fx, is).
:- op(397, fx, not).
:- op(701, xfx, then).
all summers are warm.
if it is not summer then it is winter.
now it is winter.
SWI-Prolog is kind enough to make red those op that get stored, i.e. can be queried easily. These are the higher precedence words declared: i.e. are,then,now.
?- now X.
X = it is winter.
How to represent this depends on what inferences you want to make. One of the simplest ways is
warm :- summer.
winter.
The "if not summer then winter" rule does not actually allow you to make any useful inferences, so you could just as well skip it. If you were to include it, it might be something like
winter :- \+ summer.
but since negation in Prolog is negation as failure, this might not do what you think it does if you expect the semantics of vanilla propositional logic.
winter(now).
warm(X) :- summer(X).
summer(X) :- \+ winter(X).
winter(X) :- \+ summer(X).
Would be one of the ways to do this.
In action:
6 ?- summer(now).
false.
7 ?- summer(tomorrow).
ERROR: Out of local stack
8 ?- warm(now).
false.
Here a solution without using negation, instead the universe of seasons is
specified.
season(summer).
season(winter).
now(winter).
warm(S) :-
season(S),
S = summer.
Some example queries:
?- now(S).
S = winter ;
false.
?- now(S), warm(S).
false.
?- warm(S).
S = summer ;
false.