Prolog Cafe provides the following built-in predicates that enable us to easily call Java programs from Prolog programs.
| Prolog | Java |
|---|---|
| integer | java.lang.Integer |
| float | java.lang.Double |
| atom | java.lang.String |
| list | java.util.Vector |
| java_object | Java Object |
These predicates are available from both the interpreter and the translator. For example, the following goal creates a new java frame instance, set its size to 200 × 200, and make it visible.
| ?- java_constructor('java.awt.Frame', X),
java_method(X, setSize(200,200), _),
java_get_field('java.lang.Boolean', 'TRUE', True),
java_method(X, setVisible(True), _).
X = java.awt.Frame(1402733),
True = java.lang.Boolean(1231) ?
yes
List 1[queens2.pl]is a Prolog program of N-Queens puzzle. The goal of N-Queens is to place N queens on an N by N board such that no piece attacks another. Let us show how to display the result of N-Queens graphically through cooperation with Java.
> ls QueensFrame.java queens2.pl
> javac QueensFrame.java
> java -cp .:$PLCAFEDIR/plcafe.jar:$CLASSPATH \
jp.ac.kobe_u.cs.prolog.lang.PrologMain \
jp.ac.kobe_u.cs.prolog.builtin:cafeteria
| ?-
| ?- [queens2].
{consulting queens2.pl ...}
{queens2.pl consulted, 230 msec}
| ?- show.
The goal show/0 first creates a QueensFrame object and makes it visible. And then the answer of the call queens(8,Xs) is displayed on the frame (see Figure 1[Result of queens2.pl]) by invoking the setQueens(Qs) method. The answer, a list of integers, will be automatically converted into a java.util.Vector object at that time. Finally, fail force to do backtrack for finding an another answer after waiting a minute by invoking the sleep method of java.lang.Thread.
main :-
queens(8, Qs), write(Qs), nl, fail.
show :-
java_constructor('QueensFrame', Frame),
queens(8, Qs),
java_method(Frame, setQueens(Qs), _),
java_method('java.lang.Thread', sleep(1000), _),
fail.
queens(N,Qs) :-
range(1,N,Ns),
queens(Ns,[],Qs).
queens([],Qs,Qs).
queens(UnplacedQs,SafeQs,Qs) :-
select(UnplacedQs,UnplacedQs1,Q),
not_attack(SafeQs,Q),
queens(UnplacedQs1,[Q|SafeQs],Qs).
not_attack(Xs,X) :-
not_attack(Xs,X,1).
not_attack([],_,_) :- !.
not_attack([Y|Ys],X,N) :-
X =\= Y+N, X =\= Y-N,
N1 is N+1,
not_attack(Ys,X,N1).
select([X|Xs],Xs,X).
select([Y|Ys],[Y|Zs],X) :- select(Ys,Zs,X).
range(N,N,[N]) :- !.
range(M,N,[M|Ns]) :-
M < N,
M1 is M+1,
range(M1,N,Ns).
import java.awt.*; import java.util.Vector; public class QueensFrame extends Frame { QueensPanel queensPanel; public QueensFrame() { setSize(500, 500); queensPanel = new QueensPanel(); add(queensPanel); setVisible(true); } public void setQueens(Vector queens) { queensPanel.setQueens(queens); } } class QueensPanel extends Panel { Vector qs = null; public void setQueens(Vector queens) { qs = queens; repaint(); } public void paint(Graphics g) { if (qs == null) return; int c = getSize().height / qs.size(); Color[] bg = { Color.white, Color.gray }; for (int i = 0; i < qs.size(); i++) { for (int j = 0; j < qs.size(); j++) { g.setColor(bg[(i + j) % 2]); g.fillRect(i * c, j * c, c, c); } g.setColor(Color.orange); int j = ((Integer)qs.get(i)).intValue()-1; int d = c / 10; g.fillOval(i*c+d, j*c+d, c-2*d, c-2*d); } } }
At first, we give a brief introduction to the Prolog Cafe implementation of Prolog data, called term. Please refer to Prolog Cafe API Specification in detail.
Each term is translated into a java object of classes in Figure 2[Term representation]: VariableTerm, IntegerTerm, DoubleTerm, SymbolTerm, ListTerm, and StructureTerm. The Term class, which has an abstract method unify, is a common superclass of these classes. The JavaObjectTerm class is used to represent any java instance as a term.
Basic procedure for calling a Prolog predicate p from Java is as follows:
This procedure using call and redo is based on the well-known Prolog Box Control Flow Model.
For example, List 3[Queens.java] shows code for executing a goal queens(8,Qs) from Java. Each of the answers will be repeatedly displayed after being converted to a java string.
> ls Queens.java queens2.pl
> mkdir work
> cd work/
work> java -cp $PLCAFEDIR/plcafe.jar \
jp.ac.kobe_u.cs.prolog.compiler.Compiler ../queens2.pl
work> javac -d . -cp $PLCAFEDIR/plcafe.jar *.java
work> jar cf ../queens2.jar *.class
work> cd ..
> ls
Queens.java queens2.jar queens2.pl work
> javac -d . -cp queens2.jar:$PLCAFEDIR/plcafe.jar Queens.java > java -cp .:queens2.jar:$PLCAFEDIR/plcafe.jar Queens [4,2,7,3,6,8,5,1] [5,2,4,7,3,8,6,1] [3,5,2,8,6,4,7,1] ... >
Other examples are available in the $PLCAFEDIR/examples/java directory.
import jp.ac.kobe_u.cs.prolog.lang.*; public class Queens { static void queens(int n) { PrologControl prolog = new PrologControl(); Predicate queens = new PRED_queens_2(); Term arg1 = new IntegerTerm(n); Term arg2 = new VariableTerm(); Term[] args = { arg1, arg2 }; prolog.setPredicate(queens, args); for (boolean r = prolog.call(); r; r = prolog.redo()) { System.out.println(arg2.toString()); } } public static void main(String[] args) { queens(8); } }
As mentioned above, a predicate f/n is translated into a PRED_f_n.java. Conversely, it is possible to make an user-defined built-in predicate by creating a java program named PRED_f_n.java.
Let us, for example, show how to make a built-in predicate msgbox/1 that launches a new pop-up window for confirmation.
msgbox(_).
> java -cp $PLCAFEDIR/plcafe.jar \
jp.ac.kobe_u.cs.prolog.compiler.Compiler msgbox.pl
> ls
PRED_msgbox_1.java msgbox.pl
a1 = a1.dereference(); String msg = a1.toString(); JFrame frame = new JFrame(); frame.setSize(300, 100); JOptionPane.showMessageDialog(frame, msg);
> javac -d . -cp $PLCAFEDIR/plcafe.jar PRED_msgbox_1.java
> java -cp .:$PLCAFEDIR/plcafe.jar:$CLASSPATH \
jp.ac.kobe_u.cs.prolog.lang.PrologMain \
jp.ac.kobe_u.cs.prolog.builtin:cafeteria
| ?- msgbox('hello').
yes
import jp.ac.kobe_u.cs.prolog.lang.*; import jp.ac.kobe_u.cs.prolog.builtin.*; import javax.swing.*; // Added public class PRED_msgbox_1 extends Predicate { public Term arg1; public PRED_msgbox_1(Term a1, Predicate cont) { arg1 = a1; this.cont = cont; } public PRED_msgbox_1(){} public void setArgument(Term[] args, Predicate cont) { arg1 = args[0]; this.cont = cont; } public int arity() { return 1; } public String toString() { return "msgbox(" + arg1 + ")"; } public Predicate exec(Prolog engine) { engine.setB0(); Term a1; a1 = arg1; a1 = a1.dereference(); // Added String msg = a1.toString(); // Added JFrame frame = new JFrame(); // Added frame.setSize(300, 100); // Added JOptionPane.showMessageDialog(frame, msg); // Added return cont; } }