1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
# Tutorials - Java-calls-Prolog
Assume we have a testing Prolog file with this content:
```prolog
child_of(joe, ralf).
child_of(mary, joe).
child_of(steve, joe).
descendent_of(X, Y) :-
child_of(X, Y).
descendent_of(X, Y) :-
child_of(Z, Y),
descendent_of(X, Z).
```
You may wish to load this database into an interactive Prolog session to experiment with the predicates in this database before experimenting with JPL.
## Consulting the Prolog database from its text file
In an ordinary interactive Prolog session, we would load the above Prolog database using the Prolog `consult/1` predicate, a built-in predicate in standard Prolog. Note, however, that as a Prolog predicate, "calling" `consult/1` is just an example of making a Prolog query, and this is how we perform it with JPL.
First, we construct an instance of `Query`, whose name is consult and whose arguments (just one) comprise the atom `'test.pl'`:
```java
Query q1 =
new Query(
"consult",
new Term[] {new Atom("test.pl")}
);
```
Then, we call the `hasSolution()` method of this `Query` object, which returns a `boolean` value indicating its success:
```java
System.out.println( "consult " + (q1.hasSolution() ? "succeeded" : "failed"));
```
At this point, this process may seem a bit long-winded; however, you should soon see that the classes are sufficiently general that they provide a robust and powerful interface into the Prolog engine.
## Querying the database
Using the same technique, we can query the Prolog database about inferences it can make. To ask whether the Prolog query `child_of(joe,ralf)` is true, given the above Prolog database, for example, we write:
```java
Query q2 =
new Query(
"child_of",
new Term[] {new Atom("joe"),new Atom("ralf")}
);
System.out.println(
"child_of(joe,ralf) is " +
( q2.hasSolution() ? "provable" : "not provable" )
);
```
To take an example that requires a bit more work on the part of the Prolog engine, on the other hand, we can ask whether `descendent_of(steve,ralf)` is true:
```java
Query q3 =
new Query(
"descendent_of",
new Term[] {new Atom("steve"),new Atom("ralf")}
);
System.out.println(
"descendent_of(joe,ralf) is " +
( q3.hasSolution() ? "provable" : "not provable" )
);
```
## Querying with variables
Ground queries (those without variables) like the above are relatively straightforward; they are essentially either provable or not, and there is typically no point in backtracking.
Once we use variables, however, things get a bit more complicated. Using the `Variable` class, we can construct a non ground query; and using other methods of `Query` we can obtain a solution in the form of a `java.util.Map`. If the `Query` has one or more solutions, then its `Query.oneSolution()` method returns a `Map<String,Term>` representing the first solution, otherwise it returns null:
```java
Variable X = new Variable("X");
Query q4 =
new Query(
"descendent_of",
new Term[] {X,new Atom("ralf")}
);
java.util.Map<String,Term> solution;
solution = q4.oneSolution();
System.out.println( "first solution of descendent_of(X, ralf)");
System.out.println( "X = " + solution.get("X"));
```
The `Map` contains **bindings** in the form of `Terms`, each of which is indexed by its corresponding `Variable` in the `Query`.
## Finding all solutions
The previous query finds only the _first_ solution. Often, however, one wants all solutions, or at least more than just the first.
The `Query` class also provides the `allSolutions()` method, which returns an array of zero or more `Map`, each of which represents a given solution.
In this example we reuse the query `q4`, which was reset to its initial state by the call of `oneSolution()`, and instead call `allSolutions()`, which returns an array of solutions:
```java
java.util.Map<String,Term>[] solutions = q4.allSolutions();
for ( int i=0 ; i < solutions.length ; i++ ) {
System.out.println( "X = " + solutions[i].get('X"));
}
```
If one wants not all but, say, at most `n` solutions, one could use method `nSolutions(n)`. Again it will return an array of at most `n` solution bindings:
```java
java.util.Map<String,Term>[] solutions = q4.nSolutions(20);
for ( int i=0 ; i < solutions.length ; i++ ) {
System.out.println( "X = " + solutions[i].get('X"));
}
```
Observe that even though we asked for at most twenty solutions, less could be returned since there may be less than such number of solutions.
## Iterating through solutions
Equivalently, one can obtain each solution by exploiting the `Iterator` interface, which the `Query` class implements. This will allow a Java program to iteratively go through solutions one-by-one.
In this example, we iteratively call `hasMoreSolutions()` and `nextSolution()` to exhaustion:
```java
System.out.println( "each solution of descendent_of(X, ralf)");
while ( q4.hasMoreSolutions()) {
solution = q4.nextSolution();
System.out.println( "X = " + solution.get("X"));
}
```
The `hasMoreSolutions()` method of the Query class returns a `boolean`, indicating whether there are any solutions "left" in the query. If the answer to this is 'yes', then the solution can be obtained in the form of a `Map<String,Term>` by the `nextSolution()` method.
As with any iterator in Java, it is safest to call `nextSolution()` only when it has been checked that there is indeed a "next" element in the iteration (via `hasMoreSolutions()`). Otherwise, we would run the risk of getting a `java.util.NoSuchElementException` exception.
In this final example, we reuse the previous variable `X` with a new variable `Y` in a new query `q5`:
```java
Variable Y = new Variable();
Query q5 =
new Query(
"descendent_of",
new Term[] {X,Y}
);
while ( q5.hasMoreSolutions() ){
solution = q5.nextSolution();
System.out.println( "X = " + solution.get("X") + ", Y = " + solution.get("Y"));
}
```
**Note:** when using an iterator query, the query stays open until all solutions have been retrieved or the query is closed explicitly via the `close()` method. When open, the query is attached to a Prolog engine, and there are a finite number of them, so care must be taken in a multi-threaded application to avoid a deadlock situation. Please refer to the [Multi-Threaded-Queries](TutorialMultithreaded) for details.
Also, check to check all the high-level API provided to access Prolog from Java, see the entry [Types-of-Queries:-One-shot-vs-Iterative](TutorialTypesOfQueries).
|