Java-Prolog bridge FAQ

From InterProlog Wiki
Jump to: navigation, search

How can I try/port my Prolog program ?

Just run one of the Prolog listener windows, either with runSubprocessListener.bat or runNativeListener.bat, consult your files and call your goals as you would in a shell console. Both invoke the same XSB Prolog installed in your machine.

The first uses a SubprocessEngine, which redirects Prolog I/O to the listener window, so using it feels just like using Prolog's regular top level interpreter in a standard shell console, tracer and all, except that you get the ability to use javaMessage, such as for visualization. SubprocessEngine may be useful for development.

The second uses a NativeEngine invoked by deterministicGoal, so you only get the first solution to your goals; Prolog I/O is performed in the Java console, and Prolog's regular top level interpreter is not used. NativeEngine is just about 4x faster piping data to/from Prolog, so this variant is being progressively less used.

How can I visualize Prolog structures ?

Call from a Prolog listener window:

  • browseTerm(Term) to display a term as a tree
  • browseList(List) to display a list
  • browseLiteralInstances(GroundTerm,Instances) to display a table
  • browseTreeTerm(T) to display a tree in a hierarchical multi-list browser

See #Prolog side API. Take a look at their implementation in the com.declarativa.interprolog.gui package, and in the associated Prolog file visualize.P, and develop your own Swing models based on objects specified by Prolog.

How can I make a Java program that calls Prolog ?

To develop a Java application using InterProlog you must import the relevant class packages, typically com.declarativa.interprolog and com.xsb.interprolog, and include interprolog.jar in your CLASSPATH. The other packages are needed only if you use them :) Take a look at com/declarativa/interprolog/gui/ListenerWindow.java for inspiration.

Here's a simple "hello world" Java program that uses Prolog, already included in the InterProlog examples package:

package com.declarativa.interprolog.examples;
import com.declarativa.interprolog.*;
import com.xsb.interprolog.*;
public class HelloWorld{
  public static void main(String args[]) {
  PrologEngine engine = new NativeEngine(args[0]);
  engine.command("import append/3 from basics");
  Object[] bindings = engine.deterministicGoal(
    "name(User,UL),append(\"Hello,\", UL, ML), name(Message,ML)",
    "[string(User)]",
    new Object[]{System.getProperty("user.name")},
    "[string(Message)]");
  String message = (String)bindings[0];
  System.out.println("\nMessage:"+message);
  // the above demonstrates object passing both ways; 
  // since we may simply concatenate strings, an alternative coding would be:
  bindings = engine.deterministicGoal(
    "name('"+System.getProperty("user.name")+"',UL),append(\"Hello,\", UL, ML), name(Message,ML)",
    "[string(Message)]");
  // (notice the ' surrounding the user name, unnecessary in the first case)
  System.out.println("Same:"+bindings[0]);
  System.exit(0);
  }
}

You can run it with java -classpath interprolog.jar com.declarativa.interprolog.examples.HelloWorld YOUR_XSB_DIR. The same program will run using a SubprocessEngine by changing the 6th line and passing as argument YOUR_XSB_EXECUTABLE_PATH instead.

How can I return a list from Prolog to Java?

It depends on how variant your list elements can be. Prolog imposes nearly no constraints on terms, but Java needs more structure.

The short answer to the question is: one can use the TermModel class, which is able to represent any Prolog term on the Java side, but putting the burden on Java to know about term structure. One can write something like:

PrologEngine engine = ... ... 
Object[] bindings = engine.deterministicGoal("..., buildTermModel(List,TM)","[TM]"); 
TermModel list = (TermModel)bindings[0]; 
System.out.println("Here is the result:"+list); 
if (list.isList()) { 
  // Visit the list using getChild(0) (for head) and getChild(1) (for tail)
  ...
}

(buildTermModel is a predicate that constructs a TermModel object specification for any given Prolog term.)

The longer answer involves "typing" the list elements. Suppose that the list contained just atoms, corresponding to String objects. One might write instead:

On the Prolog side:

processList([],[]). 
processList([A|L],[string(A)|LL]) :- atom(A), processList(L,LL). 
% string(S) specifies a Java String object

On the Java side:

PrologEngine engine = ... ... 
Object[] bindings = engine.deterministicGoal(
  "..., processList(List,LL), ipObjectTemplate('ArrayOfString',AS,_,[LL],_)","[AS]"); 
String[] list = (String[])bindings[0]; 
System.out.println("Here is the list of Strings:"); 
for (int i=0;i<list.length;i++) 
  System.out.println(list[i]);

For more complex list elements, e.g corresponding to instances of a. custom class, the class would need to be taught to the PrologEngine with teachMoreObjects, and a different ipObjectTemplate or ipObjectSpec goal would be used.

Why do I get a nullPointerException on startup?

Perhaps because InterProlog assumes that its own Prolog files are in a jar file, and is unable to read them.

How do I get a full object specification as a javaMessage result, instead of just an object reference ?

You need to use an extra javaMessage to obtain a full object specification; say your InvisibleObject is X and you want a specification for the referred object in S :

ipPrologEngine(E), javaMessage(E,S,getRealJavaObject(X))

How do you call goals with multiple solutions?

One can collect all solutions on the Prolog side at once and return them as a single list. For a simple implementation one might want to use a Java TermModel object to encapsulate the list. So on the Prolog side define:

nonDeterministicGoal(InterestingVarsTerm,G,ListTM) :-
  findall(InterestingVarsTerm,G,L), buildTermModel(L,ListTM).

And on the Java side do something like (assuming you wanted to collect all solution bindings for mygoal(A,B)):

String goal = "nonDeterministicGoal(A+B,mygoal(A,B),ListModel)"; 
// Notice that 'ListModel' is referred in both deterministicGoal arguments: 
TermModel solutionVars = (TermModel)(engine.deterministicGoal(goal,"[ListModel]")[0]);
System.out.println("Solution bindings list:"+solutionVars); 
...

...and at this point one can use TermModel methods (or access its two public instance variables) to visit the list and gather bindings; at the atomic level this means collecting TermModel nodes, which will be either String or numeric type wrapper objects.

Another possibility is to use the goal Java method and its SolutionIterator object

How to pass a custom object structure from Prolog to/from Java?

Make the object class Serializable, teach it to the PrologEngine, use ipObjectSpec on the Prolog side, and use deterministicGoal Object[] arguments and/or return values. See BackEnd.java in com/declarativa/interprolog/examples

Why do I get an IllegalAccessException when using javaMessage?

Make sure your class and the methods invoked by javaMessage are 'public'. Prolog->Java calls go through Java's Reflection mechanisms so all invoked classes/methods must be public, including constructors.

Why can't I obtain instance variables in Prolog for an object returned by javaMessage?

When you create a Java object from the Prolog side, the message result on the Prolog side is always an InvisibleObject specifier, which encapsulates a compact reference to the Java object - just an integer, which is a key into an ObjectRegistry, an object table kept by a PrologEngine. So the object variables are not returned to Prolog.

But if you send the InvisibleObject back to Java as a javaMessage argument it will automatically be converted into the real object just prior to invoking the Java method. And so in both directions communication involves a few bytes, rather than perhaps a few K of the fully serialized objec; if you want this, see #How do I get a full object specification as a javaMessage result, instead of just an object reference ?

Where should I put a Prolog file that my Java app uses?

Place it in the same directory and jar file as the Java package more closely related to the file, and load it into the PrologEngine with consultFromPackage(filename,MyClass.class)

Can I build Applets with InterProlog?

Not in general. InterProlog needs access beyond the security permissions of typical Java applet viewers such as web browsers. In principle it should be possible to sign an applet to enlarge its permissions, but anyway the Prolog system must be installed in the machine running the applet, which probably makes it less appealing.

However it is possible to write a simple Java server application running InterProlog and accepting connections from applets. Beware though that although PrologEngine handles deterministicGoals/javaMessages from multiple Java threads, their Prolog handling is sequential, so it is possible for a hanging goal (say, because it calls some Java method that blocks waiting for something that never comes) to hang others.

How do I change and recompile InterProlog ?

Use the enclosed Ant build.xml script.

The InterProlog Java-Prolog bridge is open source, so if you're ready to share your additions within the same licensing model feel free to contribute them to javabridge@interprolog.com

How do I know from Java which Prolog system is being used by a PrologEngine?

Just test the class of its peer:

if (engine.getImplementationPeer() instanceof XSBPeer){
 // XSB Prolog
}

Alternatively, teste the engine class (e.g. XSBSubprocessEngine for XSB Prolog).

Is technical support and project coaching available ?

Yes. Simple technical support and project guidance questions are usually answered within a couple of days, and bugs tend to get fixed. Faster or deeper support and development aid is available through InterProlog Consulting.