USER GUIDE
February 2008
About BinPrologJ
BinPrologJ is multi-threaded compiled Prolog
system with powerful Object Oriented extensions, intended to be used as
a flexible scripting tool for gluing together knowledge processors in distributed
applications. Its high level, portable, secure networking layer
provides intelligent interoperation between Java and .NET components on
Windows, Mac OS X, Linux/Unix and Java enabled PDAs and cell phones.
Prolog threads are coordinated through blackboards, local to
each process. Associative search based on term unification (a
variant of Linda) is used as the basic synchronization
mechanism. Threads, blackboard and networking operations are controlled
with lightweight, fast bytecode Prolog interpreters. The synergy of
these features makes BinPrologJ a convenient development platform for distributed
AI, and in particular, for building intelligent autonomous agent
applications.
BinPrologJ supports multi-user synchronized
transactions and interoperates with the C-based version of BinProlog, a high
performance, multi-threaded Prolog system, well suited
for large volume server side operations. BinProlog is a robust, high
performance commercial software product of BinNet Corporation. Please
contact BinNet Corporation through our Web pages at http://www.binnetcorp.com, by
phone at +1 (940) 300-7171 or by e-mail to binnetcorp@binnetcorp.com
for licensing and price information.
The Prolog compiler integrates a high performance pure
Java based Prolog system featuring multiple logic engines and dynamic
databases, with high level networking operations and a GUI development
library. Packaged as a 450K Java+Prolog bytecode library, it is a
self-contained, lightweight, knowledge and interaction processing component,
featuring:
- Fast WAM based multiple, reentrant Prolog engines, Object
Oriented Prolog extensions
- Synchronized, flexible multi-threaded execution
- Fully dynamic data areas, heap, symbol table, code area and
external object garbage collection
- Extensibility and interoperation with Java through
robust Reflection based bi-directional interface
- High level networking through remote predicate call
mechanism
- Distributed blackboard technology providing powerful
associative search on structured data
- Agent coordination language, with ability to express
waiting and notification on complex conditions
- Code and data fetching over the Internet, ability to see URLs
as ordinary files
- Built-in lightweight Web server supporting your BinPrologJ
applets
and Prolog Server Agents base Web services
- Compilation to Java, ability to deploy BinPrologJ as a
self-contained
Applet, Webstart application or .NET executable
- Byte code compression and encryption ensures compact and secure
deployment of large Prolog knowledge bases
- The Prolog GUI library
- Various extensions like the Prolog3D Java3D-based animation and
graph layout tool
Getting started
Installation and essential files
Make sure you uncompress the provided *.zip or *.tar.gz file containing
BinPrologJ . The toplevel interaction starts with something like
java -jar prolog.jar (this loads Prolog's bytecode from compressed and
encrypted Java classes)
or
java -classpath prolog.jar
prolog.kernel.Main(on a Java platform)
or
netprolog.exe
(on a .NET platform)
Note that all Prolog and Java files are in fact in the prolog.jar
file - once the classes are loaded by Java, Prolog extracts its own
bytecode files! To run Prolog from another directory, put
prolog.jar in directory /bin together with prolog.bat in Windows (or a
similar script in Unix) and then just type
prolog.bat
You might need to adapt this script with other versions of
Java or on other platforms. If you prefer, you can use the prolog.bat
or netprolog.bat (for .NET execution) scripts - once you
edit the absolute path information to reflect the directory where you
install them.
Quick info - if you want to try out things right
away. Look at the various *.bat files for hints on how to start the
various components.
- For multi-user installation modify prolog.bat
to reflect OS specifics and prolog.jar's location information, then add
it somewhere in your PATH. This will allow running it by typing prolog.bat
from any directory. Try appletgo.bat to see a number of Prolog
applets locally with your appletviewer. Note that the .NET version
netprolog.exe requires access to the file psrc/wam.bp from where
it extracts its compiled Prolog bytcode components.
.NET installation:
Make sure the .NET framework and the J#
redistributable runtime have been installed on your computer.
The are freely available from the download area at
www.microsoft.com. From the "prolog" directory type netprolog.exe. At the ?-
prompt, type something like vq8:go
to see the 8-Queens program running!
Embedded Prolog component installation:
Simply copy the selfcontained prolog.jar file to the required
component directory, assuming that the component managment software
starts Prolog in a way similar to java -jar
prolog.jar. This technique is usable for tools like Webstart
or for deploying Prolog as a server side knowledge processor.
Running Prolog as an Applet:
A good way to deploy Prolog as an applet is using something like the
following:
<APPLET
ARCHIVE="prolog.jar"
CODE="prolog.kernel.PrologApplet.class"
HEIGHT="220"
WIDTH="220"
>
<PARAM
NAME="command"
VALUE="applet_ide"
>
</APPLET>
This applet will start by running the command parameter applet_ide as the initial goal.
Running Prolog Applets from the Web using Prolog's Embedded HTTP
Server
If you do not have a Web server or want to avoid the hassle of
configuring one, you can activate the embedded HTTP server allowing
your users to run Prolog applets directly, with something like:
?-run_http_server(8001).
or
?-bg(run_http_server(8001)).
to run the server as a background Prolog thread. You can also add a
remote predicate with bg(run_server)
to ensure that your clients can keep persistent state on the
server using a variant of the remote_run
command.
Exporting local services with BinPrologJ's TCP-IP tunneling
BinPrologJ supports a simple TCP-IP tunelling API to
export services provided by servers behind a firewall
(in particular BinPrologJ's own Prolog remote predicate call
server, or its HTTP server usable to deploy BinPrologJ applets or
server side Prolog agents). The API consists of server
and client side tuneling components:
server_tunnel(ServerPort,LinkServerPort,ServerTunnel):
Creates a server side TCP-IP tunnel which maps ServerPort
to LinkServerPort. When a client connects to LinkServerPort,
it will be able to map all the services of a server it has access to
(usually behind a firewall or NAT) as if they were provided on ServerPort.
This component is meant to be used on a machine visible on the net to
which services behind firewalls can connect and become visible. The
returned ServerTunnel can be used to stop the
(background) threads created to support the tunnel.
client_tunnel(LinkHost,LinkPort,LocalServer,LocalPort,ClientTunnel):
Creates a client side TCP-IP tunnel which maps LinkHost,
LinkPort, to LocalServer, LocalPort
where a server (usually behind a firewall or NAT) listens. This client
connects to LinkHost, LinkPort, and
remaps the services at LocalServer, LocalPort
as if they were provided on ServerPort on the LinkHost
machine. This component is meant to be used on a machine invisible on
the net (behind firewalls or NAT). The returned ServerTunnel can be
used to stop the (background) threads created to support the tunnel.
stop_tunnel(Tunnel): Stops the threads supporting a
server or client side tunnel.
For instance, you can start on your real "server" machine with fixed
IP address and domain name ( let's say: server.example.com) with something
like:
prolog.bat
?-server_tunnel(5555,4444,R).
?-server_tunnel(8888,7777,R).
Let's assume that on the client machine (let's say "localhost"), you run an Apache
server on port 80 and a BinPrologJ Web server on port 81, which you
have
started in its own window with:
prolog.bat
?-run_http_server(81).
Then if you run on the client machine (localhost) in a separate window,
something like
?-client_tunnel('server.example.com',4444,localhost,80,R).
?-client_tunnel('server.example.com',7777,localhost,81,R).
you will be able to tunnel the services form localhost to server.example.com (visible on the
net) where you will see the
tunnelled Apache server as:
http://server.example.com:8888/
and the tunelled Prolog server as:
http://server.example.com:5555/
iPAQ Pocket PC installation:
Make sure the JEODE Java plugin is installed to your
iPAQ from the iPAQ distribution CD or by obtaining it from www.insignia.com. Then, simply
copy with ActiveSync the directory pocketProlog to the iPAQ
FileStore. Navigate with the iPAQ File Explorer to the pocketPrologdirectory,
in which you can find and click on the pprolog script. Type
something like vq8:go to see the
8-Queens program running! To change this default installation edit the pprolog.lnk
file on the host to which the iPAQ connects to reflect a different
location.
Key BinPrologJ components - (section relevant ONLY for
owners of BinPrologJ Full Source license)
The core of BinPrologJ is in the Java classes inside the
subdirectory prolog.kernel. Look
at the BinPrologJ class
documentation in directory doc. The most
important Prolog files, allowing you to
configure/fix problems with BinPrologJ are in directory psrc
- containing the definition of most built-ins implemented in Prolog. If
you have the BinPrologJ sources, the essential files to look at
are Main.java,
Top.java,Machine.java in directory prolog.kernel and
the psrc/refl.pl showing how to extend
BinPrologJ with new Java operations using Java's Reflection
abilities.
It also contains multi-threading and networking code as well as
(minimal) Personal Java compliant Prolog GUI toolkit - which can run
happily from virtually any browser and even on Java enabled PocketPC
PDA's like Compaq's iPAQ.
Extending BinPrologJ
A new, reflection based extension mechanism
has been added to BinPrologJ. In fact it is now used to provide some
key
internal components of BinPrologJ itself, like multi-threading and
networking.
Third party BinPrologJ extensions are collected in a separate
directory tree xprolog (obtained by expanding xprolog.zip). A
quick way to add your own extensions is to clone one of them and adapt
the builtins and related Prolog script files.
Using BinPrologJ in command line mode:
Entering a query:
At the prompt "?-" type in a one line Prolog query, as usual, for
instance, something like:
?- write(hello),nl.
Compiling a new program:
?-[<myprog>].
will read in memory the file <myprog>.pro program replacing
similarly named predicates with new ones.
If you start BinPrologJ with its visual environment, try
something like:
?-ide.
to launch an instance of the IDE, or
?- vq8:go.
to run a visual N-Queens program and
?- vtetris:go.
to run a Visual Tetris Agent demo. Note that the
<module>:<predicate> notation allows running multiple
Prolog applications in different code spaces.
If you have Prolog files in multiple directories you can also add
them to the end of BinPrologJ's search path with:
?- add_to_path('<mydirectory>').
On the other hand,
?-path_element(Directory).
will return one by one the directories in the current path. You can
add to the top of your search path with:
?- push_to_path('<mydirectory>').
and delete from it with
?- del_from_path('<mydirectory>').
All subsequent references to compile, consult and
<module>:<predicate> will take into
account the current path.
Note that by default BinPrologJ's toplevel is non-interactive - i.e.
it
prints all solutions to a query containing variables. You can change
this by typing:
?- interactive(yes).
Using BinPrologJ through an applet
Type appletviewer DemoGUIApplet.html . Enter, for instance, in
the query window:
append(Xs,Ys,[1,2,3]).
You will see the applet displaying the results. Applets can load
files located at the site where they originate from. Try
?-vq8:go(12).
to compile over the net and run the N-queens program with 12 queens.
To launch an instance of a simple IDE with embedded editor and query
processor, type
?-ide.
Building simple Prolog programs with BinPrologJ
With the editor of your choice create a text file called simple.pro,
with the following content:
c(X):-a(X),b(X).
a(1).
a(2).
a(3).
b(2).
b(3):- !.
b(4).
In a shell window (DOS command, csh, bash etc.), type jc.bat
to launch the standalone command line BinPrologJ toplevel, prompting
you
with "?- " to enter commands/queries. To load the file type:
?-[simple].
then try the query:
?-c(X).
Example of reading/writing to files:
BinPrologJ can read files or URLs (as well as subcomponents of
compressed ZIP or JAR files or URL) and write files in command line
mode. In applet mode BinPrologJ can only read files described as
URLs,
from from the directory it comes from. Try:
?-tell('example.txt'),write(example(one)),write('.'),nl,told.
followed by:
?-see('example.txt'),read(X),seen,write(X),nl.
BinPrologJ can open a URL over the net, in a way similar to file.
Try:
?-see('http://yahoo.com'),get0(X),get0(Y),seen,put(X),put(Y).
to print out a HTML file fetched directly from the Web.
?-token_of('http://yahoo.com',Token),println(Token),fail.
will get a token at a time from a Web page and print it out. With
this, writing your own Web data extractor in BinPrologJ is only a few
lines
away!
Creating Standalone BinPrologJ Applications
BinPrologJ's binary Prolog code is stored in wam.bp (as well as in prolog.jar in
encrypted and compressed form, to allow running even in the absence of
the wam.bp file). The end
of this file also contains directives instructing the loader to
link the code in the BinPrologJ's internal code area. The ucompile/3 operation merely
concatenates newly generated bytecode files with the current basic
bytecode file and as such allows creating standalone compiled
applications. Here is the main command:
ucompile(InFiles,BasicFile,OutFile)
For instance, if your application containing only the file
hello.pl is located in directory bin, you can type:
?-ucompile(['hello.pl'],
'wam.bp', 'hello.bp').
After compilation, to run Prolog code from the resulting bytecode file
(now containing both BinPrologJ's kernel and you application's
bytecode) you will need to pass the name of the new bytecode file
as a parameter to BinPrologJ as in:
java -cp ".;prolog.zip"
prolog.kernel.Main hello.bp
or by
using a script like urun.bat:
urun.bat hello
Please make sure you backup you wam.bp
file before experimenting with this command.
Saving and restoring BinPrologJ's state using Java serialization
All BinPrologJ classes are serializable - you can save BinPrologJ's
state (code
compiled to memory + dynamic database) with the command. serialize(myFile) which creates myFile.jc in the current directory
and then resume from the saved state file by passing <MyFile>.jc as a command line
parameter to BinPrologJ like in: java
-cp
prolog.jar prolog.kernel.Main myFile.jc. Such code is loaded
significantly faster than by calling the compiler.
Classes, Instances and Inheritance in BinPrologJ's Object Oriented
Prolog
BinPrologJ features a simple, elegant and fast Object Oriented
Prolog layer - built as a natural extension to ISO Prolog. Classes are
just Prolog files with include declarations - almost no changes
are required to reorganize your existing Prolog code in an Object
Oriented style. As the dispatching of method calls is handled at
compile time and instances are lightweight, BinPrologJ 's Prolog
Objects
are extremely efficient. Prolog class files can be located at arbitrary
URLs on the Web - you can inherit and override from a virtually
unlimited library of existing Prolog files. And what if cycles will
form? Not a problem! BinPrologJ supports multiple cyclic
inheritance
for building in a scalable way, an arbitrary network of Web or file
based interdependent Prolog classes!
A class foo is
associated to each Prolog file (or URL) let's say foo.pl. In a way similar with
compiling a Prolog file in a conventional way with ?-compile(foo), the user can enter a
default instance of the class foo with
?-enter_class(foo).
or call code in it (like in the presence of a
conventional module system) from outside with
?-foo:<predicate>.
If foo.pl contains :-[<superclassfile>] declarations, let's
say something like :-[bar], definitions not found in foo will be searched
in bar. As files and URLs are treated in similar ways,
inheritance directives like:-['http://www.my_url.com']can refer to non-local URLs as well.
ISO Prolog's :-initialization((<Goal>)) declarations are processed (in reverse order) after
collecting them from included files - as a mechanism of class level
initialization, shared among all instances. Code added with assert/1
in such initialization/1 calls will be visible in all instances.
Code inheritance is handled at compile time
- through a special ocompile/1 command which reinterprets include directives
like :-[<file>] as inheritance from other Prolog files/classes.
Classes are compiled on the fly, at the first use of a class or
creation of a new instance.
The multiple cyclical depth first
inheritance mechanism is implemented by keeping the path consisting
of the list of visited includes, when (at compile time) predicates not
defined locally, are brought from files or URLs. In the presence of
multiple includes, a "depth-first" order for finding definitions
ensures that a dominant main inheritance tree prevails in case of
ambiguity. This concept of cyclical inheritance allows reuse of
Prolog code located virtually everywhere on the Web from a local
perspective.
Constructors are simply predicates of
various arities having the same name as the file (or URL). Constructors
(of any arity) are inherited, if not provided. They can
freely call constructors defined in their super classes using their
predicate names, same as the ones of the superclasses' names.
The recommended style is to have lower arity constructors call higher
arity ones with some constant default parameters. No special
action is provided (and this is different from Java!) for no-arg
constructors of supers, except that they are inherited like
any other constructors. It is a good programming practice to share some
common initialization code among constructors - like for instance
initialzing fields, or use ISO Prolog :-initialization(Goal)
directives to initialize fields.This style ensures that fields defined
locally or in the main inheritance chain will prevail. Programmers
should initialize fields in constructors or initialization
directives, as attempts to access unitialized fields trigger runtime
exceptions (rather that simply failing).
Instance Fields are local to each
instance. A set operation <field
name> <= <value>
and a get operation <field
name> => <Prolog variable> are provided, like in:
radius <= 99
radius => R.
Reference to uninitialized fields results
in a runtime exception.
Assert/1 and
other database operations are local to instances - but the
results of class level asserts are visible in instances - until overridden by a
local assert with the same predicate name and arity.
To keep the object model simple, we have not
implemented public, private or final modifiers. This can be
provided in the future if requested by users. Other, more precise
access and security control mechanisms will be added in the future in
the context of distributed objects and agent programming constructs.
Instances are created from Constructors (same as class
names if havin no arguments, and having the main functor
the same as the class name if having arguments) with the new/2 and
renew/2 commands:
new(Constructor,Instance) - which
automatically loads te code when the first instance is created and
reuses it otherwise
and
renew(Constructor,Instance) - which forces
refreshing the code for the class, before creating the instance
In the process, an internal Class handle is created and if neaded
the code for the class is compiled on the fly and attached to it.
You can interact with Instances of Prolog Classes in
two ways, as shown in the following examples (see files like queue.pl,stack.pl
in classlib for more details).
?-enter_instance(queue).
?-add(a).
?-add(b).
?-remove(X).
?-show.
?-exit.
?-
or call code in it from outside as in:
?-new(queue,Q),Q:add(a),Q:add(b),Q:remove(X),Q:show.
Here is a simple example of 2 Prolog classes
circle.pl inheriting from shape.pl.
% file shape.pl
shape:-
centerX<=0,
centerY<=0.
show:-
centerX=>X,
centerY=>Y,
println('I am a shape at'(X,Y)).
move_to(X,Y):-
centerX<=X,
centerY<=Y.
% file circle.pl
:-[shape].
circle :- radius<=1.
circle(X,Y,R):-
centerX<=X,
centerY<=Y,
radius<=R.
show:-
centerX=>X,
centerY=>Y,
radius=>R,
println('I am a circle at'(X,Y,R)).
A query like:
?-
new(circle(1,1,5),Circle),Circle:show,Circle:(move_to(2,2),show).
will produce:
'I am a circle at'(1,1,5)
'I am a circle at'(2,2,5)
as expected, by overrding show/0 and
inheriting move_to/2.
Class Fields are shared among
instances. In fact, they are just instance fields belonging to instace
0 - which keeps the state of the class itself. A class field set
operation <field name> <==
<value> and a class field get
operation <field name> ==>
<Prolog variable> are used as
in:
instance_count <== 10
instance_count ==> R.
When performed from instances of a given
class, these operations are applied to the fields of the class,
not the instance. Like static variables in Java, they refer to
data shared among all instances of a class. Reference
to uninitialized fields results in a runtime exception.
Backtrackable Field Assignments
Undoables are special fields local to
each Prolog Engine providing backtrackable destructive
assignment. A set operation
<field name> <=# <value> and a get operation <field name> #=> <Prolog
variable> are provided, like in:
?-maybe <=# blue, maybe
#=> Color.
returning Color=blue.
Assignement to undoables is
backtrackable - this means that something like:
?-maybe <=# blue, fail ; maybe #=> Color.
will fail, without provinding a value to
Color. Contrast this with conventional field assignment which survives
backtracking, which means that:
?-maybe <= blue, fail ; maybe => Color.
will return Color=blue. Their implementation uses the public interface prolog.kernel.Undoable
which can provide action on baktracking services to a user's Java
objects. Java objects implementing this interface should provide two
methods: undo() which will be called each time backtracking
moves to the next clause of a given choicepoint and and done()
which is called when the current choicepoint is popped off the stack. A
user can register such objects (created using BinPrologJ's Reflection
based
interface) with something like add_undoable(<MyUndoableObject>).
Assumming this happens in the first clause of a predicate, for each
subsequent failure, the object's undo() method will be called.
The object's done() method will be called only once, after all
clauses of the predicate have been explored.
Assumption Grammars and DCGs
BinPrologJ supports BinProlog-style assumption
grammars as an extension to traditional Prolog DCGs. The main
difference with BinProlog is tha the Assumption Grammar API works only inside
DCG rules (clauses created using -->/2 instead of :-/2
) and their scope always extends over the "current AND-continuation" -
i.e. while the current computation is succeeding. The API
consists in a set of backtrackable operations, which enhance
DCG rules by providing a temporary database where information aquired
during the parsing process can be added, updated and queried. The API
distingushes between "linear assumptions" usable at most once once -
which bind variables, and "intuitionistic" assumptions - which can be
matched by queries indefinitely (unless removed on backtracking).
Assumption Grammar operations provide, together with the use of
overriding of DCG rules by organizing them in Prolog classes, a
powerful Object Oriented Logic Grammar mechanism.
Assumption Grammar API (operations only
usable inside DCG rules):
'#<'(Xs): sets the DCG token list to be Xs
'#>'(Xs): unifies current DCG token list
with Xs
#X: matches X against current DCG token
'#+'(X): adds 'linear' assumption +(X) to be
consumed at most once, by a '#-' operation
'#*'(X): adds 'intuitionisic' assumption *(X)
to be used indefinitely by '#-' operation
'#='(X): unifies X with any matching existing
or future +(X) linear assumptions
'#-'(X): consumes +(X) linear assumption or
matches *(X) intuitionistic assumption
'#?'(X): matches +(X) or *(X)
assumptions without any binding
The file progs/ag_parser.pl
shows a Prolog complete parser and tokenizer written using BinPrologJ's
Assumption Grammars. Among the advanced features implemented: regular
expression processing and use of assumptions to create unique variables
from variable tokens with identical names.
Multiple Databases in BinPrologJ
BinPrologJ supports multiple databases
directly - in conventional Prolog style - i.e. something like
?-Db=test_db, db_assert(Db,a(1)), db_clause(Db,a(X),B) .
which will assert a(1) in database Db and then bind X=1 and B=true.
BinPrologJ also provides fast loading and saving of password
protected databases with:
?-db_xsave(Db,File,Pasword).
which saves a protected databased named Db to a file, and
?-db_xload(File,Db,Pwd).
which loads from a file or url URL a protected database named Db.
Multiple Engines, Answer Generation and Control
Independently of its multi-threading mechanism,
BinPrologJ provides first order engines - separate
instances
of its dynamically growing/shrinking runtime system (heap,stack,trail)
which can be controlled through the following API:
- new_engine(Instance,AnswerPattern,Goal,EngineHandle):
creates and returns a new engine based on code and dynamic database
state associated with a Prolog class instance
- get(EngineHandle,Answer): asks an
engine for a new Answer, which will be of the form the(AnswerPatternInstance)
on success and which will be no on failure as well on any call
after failure occurred
- stop(EngineHandle): makes
sure the engine is stopped. Only no answers will be available
from the engine in the future.
- return(Answer): initiated by the
engine - which acts such that the next get/2 of the parent will
obtain a copy of Answer. Note that engines are fully reentrant -
in particular, the parent can force the engine to resume its work with
another get/2 request - in which case the engine performs as
if the return/1 statement were not in effect.
Example:
?-
new_engine(X,(member(X,[1,2]),(X=1,return(good(X));X>1)),E),get(E,A),get(E,B),get(E,C),get(E,D).
A = the(good(1)) B = the(1) C =
the(2) D = no E = 1331 X = _120 ;
This kind of functionality seems the simplest way to implement some
agent-style control mechanism on top of Prolog - it provides a
minimal set of language constructs for the kind of control users
want to have interactively over Prolog's answer production.
Threads and Hubs
BinPrologJ supports a simple multi-threading model, given by the
following API:
- bg(Goal,ThreadHandle): launches a new thread executing
Goal and returns a ThreadHandle to it
- hub_ms(Timeout,HubHandle): constructs a new Hub returned
as a HubHandle - a synchronization device on which N consumer threads
can wait with collect(HubHandle,Data) for data produced by M
producers providing data with put(HubHandle,Data). However,
if a given consumer waits more than Timeout miliseconds it
returns and signals failure. As usual in Java, 0 timout means
indefinite suspension.
- current_thread(ThreadHandle): returns a handle to the
current thread - might be passed to another thread wanting to join this
one.
- join_thread(ThreadHandle): waits until a given thread
terminates.
- sleep_ms(Timeout): suspends for Timeout milliseconds,
while consuming minimal (practically no) CPU power
Thread Coordination with Blackboards
Blackboards are global (one per BinPrologJ process) databases which
provide
thread coordination through the following (extended Linda) operations:
- in(Pattern): waits for data on the blackboard which
matches (through unification) Pattern
- out(Pattern): puts for data on the blackboard and
possibly resumes a thread waiting with in/1 if Pattern matches
- all(Pattern,Matches): returns a list of terms on the
blackboard ready to match Pattern or an empty list if none matches.
Such data has been put on the blackboard using out/1
operations.
- wait_for(Term,Constraint) :waits
for a term on the blackboard, such that Constraint holds
- notify_about(Term) : notifies
a suspended matching wait_for(Term,Contraint), if Constraint
holds, that Term is available
Blackboard operations can be combined with remote_run remote
predicate calls to allow interaction between threads distributed in
different processes on the same or on different computers on the net.
Threads can be launched locally or remotely with bg operations.
Client-Server Programming with Remote Predicate Calls
BinPrologJ supports a simple client-server Remote Predicate Call
mechanism given by the following API:
- run_server(Port,Password): runs a server on a given Port
and with given Password (to be matched by connecting client queries)
- run_server(Port): runs a default server on given Port
- run_server: runs server on default port
- remote_run(Query): asks the default server to run Query
and bind variables with returned result
- remote_run(Host,Port,Answer,Goal,Passwd,Result): asks a
server waiting on Host, Port to execute Goal and return a Result of the
form the(AnswerInstance) if the query succeds or no if
it fails. The returned Term answer instance contains a copy of Answer
with bindings resulting of the execution of Goal. Note that an implicit
once/1 operation is used on Goal as only the first solution
is returned.
A slightly more efficient client-server API that reuses sockets
consists of the following:
- rpc_server(Port,Password): runs
a socket reusing server on a given Port, with given Password
- start_rpc(Host,Port,Password),rpc(G1,rpc(G2)...,rpc(Gn),stop_rpc:
sends G1,G,...Gn
goals to be run on Host,Port
provided that Password matches
the server's password
Sharing a BinPrologJ Shell Server through Remote BinPrologJ Shell
Clients
BinPrologJ provides full redirection of I/O from a BinPrologJ
application
working as a shell server
to one or more others working as shell clients. This allows
seeing/debugging/running a program by multiple users (for instance a
teacher and a group of students).
Server Window:
?- shell_server.
Server started on port: 6001
Client Window
?- ?- shell_client.
?- assert(a(99)).
yes
?- a(X).
X = 99
;
no
Note that asserted facts will become visible to all clients. BinNet
Corp. also provide lightweight (less then 10K) Java and .NET clients
allowing to run server side Prolog
applications with minimal client processing effort (like for
instance in the case of wireless or cellular phone enabled PDAs).
Calling Java from BinPrologJ by using Reflection
The Reflection based API connecting compiled Prolog code directly to
arbitrary Java classes, objects, methods, fields is very simple but
very powerful. Data-types are converted automatically to their most
natural equivalents (Java Strings to/from Prolog constants, Java
integers and doubles to their Prolog numerical equivlalents etc.). If a
given method's parameter signature triggers a Java exception, the
interface attempts exhaustive method search and data conversions to
invoke what the programmer "means".
- new_java_class(Name,Cls): given a Name (Prolog
constant), returns a handle to a Java class Cls
- new_java_object(Cls,Args,Obj): returns Obj, an
instance of class Cls by calling a constructor with Args.
If Args=none, a constructor with no arguments is called,
if Args=args(A1,A2,...An) then a matching constructor with
arguments A1,A2...An is called, after appropriate conversions
- invoke_java_method(Class,Obj,MethName,Args,Answer): Invokes
on Obj a method named MethName defined in Class with
Args and unifies Answer with the value returned by
the method (which can be one the special constant '$null'). If Args=args(A1,A2,...An)
then a matching method with arguments A1,A2...An is called,
after appropriate conversions. If the Class parameter is absent, it
will be guessed using Obj's getClass() method.
- get_java_field_handle(Obj,FieldName,FieldHandle): Given
an object Obj and a FieldName it returns a FieldHandle(a
handleto a java.lang.reflect.Field object) on which various get
and set methods can then be invoked
- delete_java_class(Cls,YesNo): deletes Cls from
the persistent object handle table. YesNo=true indicates
success. YesNo=fail indicates failure of the delete operation
- delete_java_object(Obj,YesNo): deletes Obj from
the persistent object handle table. YesNo=fail indicates
failure of the delete operation.
A more convenient Prolog layer provides an extended REFLECTION API -
which also shows how the main builtins are used.
/*
add new object using convenient
<className>(A1,...An) syntax
*/
new_java_object(ClassName,Object):-
atom(ClassName),!,
new_java_class(ClassName,Class),
new_java_object(Class,void,Object).
new_java_object(ClassAndArgs,Object):-
functor(ClassAndArgs,ClassName,_),
new_java_class(ClassName,Class),
new_java_object(Class,ClassAndArgs,Object).
/*
invoke static or dynamic Java method
using
more natural
<methodName>(A1,...An) syntax
*/
invoke_java_method(ObjectOrClass,MethodName,Result):-
atom(MethodName),!,
invoke_java_method(ObjectOrClass,MethodName,void,Result).
invoke_java_method(ObjectOrClass,MethodAndArgs,Result):-
functor(MethodAndArgs,MethodName,_),
invoke_java_method(ObjectOrClass,MethodName,MethodAndArgs,Result).
/*
Get the content of a (public) Java field
after obtaining a handle to it
*/
get_java_field(Object,FieldName,Val):-
get_java_field_handle(Object,FieldName,Handle),
invoke_java_method(Handle,get(Object),Val).
/*
Set the content of a (public) Java field
to a new value, after obtaining a handle
to it
*/
set_java_field(Object,FieldName,NewVal):-
get_java_field_handle(Object,FieldName,Handle),
invoke_java_method(Handle,set(Object,NewVal),_).
/*
Get the a handle to the class to which
object O is an instance
*/
get_java_class(O,Class):-
invoke_java_method(O,getClass,Class).
Wrapping Java Classes as BinPrologJ Classes using Reflection
A natural way to interface Prolog with Java is by building Prolog class
wrappers around Java classes. We can build a wrapper class using
BinPrologJ's Object Oriented Layer to provide in Prolog the "same"
functionality as it does in Java. The following example (code in classlib/hashtable.pl ) shows
how we can map Java's Hashtables to Prolog classes.
/*
Example of wrapper for a Java class as a
Prolog class
*/
hashtable:-
new_java_class('java.util.Hashtable',C),
new_java_object(C,void,JavaHashTable),
table<=JavaHashTable.
put_data(Key,Data):-
table=>T,
invoke_java_method(T,put(Key,Data),_Result).
get_data(Key,Data):-
table=>T,
invoke_java_method(T,get(Key),Data).
remove_data(Key):-
table=>T,
invoke_java_method(T,remove(Key),_Result).
Example of Prolog interaction:
?-
new(hashtable,H),H:put_data(hello,99),H:get_data(hello,X).
H = '$instance'(hashtable@554,1) X = 99 ;
Extending BinPrologJ's functionality through Reflection
Here is a (simplified) example on how we build an interface to
BinPrologJ's
own networking classes, using this reflection based Java calling
interface.
new_server(Port,Server):-
new_java_object('prolog.kernel.Transport'(Port),Server).
new_service(Server,Service):-
new_java_object('prolog.kernel.Transport'(Server),Service).
read_from(Service,Query):-
invoke_java_method(Service,read_from,Query).
write_to(Service,Answer):-
invoke_java_method(Service,write_to(Answer),_).
% server side RPC handling
run_server(Port,Password):-
new_server(Port,Server),
repeat,
new_service(Server,Service),
bg(handle_query(Service,Password)),
fail.
Take a look at the Java files in directory psrc
for more examples of built-ins written directly in Prolog.
Calling BinPrologJ from Java and back
This basic String based interface allows sending a query to BinPrologJ
and
getting a String back as based on the (first) answer to your queries.
Note that BinPrologJ will call back (through the Prolog predicate go/0)
the
static sayHello() method in class Hello.java.
Hello.java file:
import java.io.*;
import prolog.kernel.*;
public class Hello {
public static String sayHello(String who) {
System.out.println("Hello "+who);
return "got "+who;
}
public static void main(String[] args) {
Machine M=Top.initProlog(args); // args can be
null
System.out.println(M.run("println(hello)"));
//calls BinPrologJ
System.out.println(M.run("X :- X is 1+1"));
//gets a result from BinPrologJ
M.run("mcompile('hello.pl')");
M.run("go");
}
}
hello.pl file:
go:-
call_java_class_method('Hello',sayHello('BinPrologJ'),Result),
println('back to BinPrologJ'),
println('Java said: '=Result).
Java-Prolog Interface Techniques for Power Users
If your application needs very high performance and/or complex data
exchanges between Java and Prolog you can adapt the following examples
(provided together with a J++ 6.0 project and some simple script files
for Windows) in the directory xjinni2k/JavaCallsBinPrologJAndBinPrologJCallsBack
). Here are some scenarios of what can be achieved:
- a Prolog term can be built in Java or read from a String
- such terms can include handles to arbitrary Java objects to be
passed to Prolog
- methods of Java object and class handles can be called from
Prolog using BinPrologJ's Reflection based Java interface
- handles to Java objects and classes can be asserted to Prolog's
dynamic database or added as fields of Prolog Objects
- bidirectional, multi-threaded call/callback exchanges are
prossible and can be initiated from either side
- applications can embedd BinPrologJ and take advantage of this
interface by simply copying the prolog.zip runtime in the application's
directory and adding it to the classpath
The Java side: file MyMain.java
import prolog.kernel.*;
import java.util.*;
/**
* Shows examples of calls form Java to Prolog and back
*/
public class MyMain {
/**
* this class embeds BinPrologJ into your application
* make sure prolog.jar is copied in THIS directory
* because that's where BinPrologJ will look for its
Java
code
* as well as the for its Prolog bytecode.
* Start BinPrologJ with: go.bat, then run.bat
*/
public static void main (String args[]) {
Machine M=Top.initProlog(args);
if(M!=null) {
String query="compile('myMain.pl')";
testJavaPrologInterface();
M.run(query);
Top.toplevel(M);
}
JavaIO.halt(0);
}
/**
* just makes printing easier
*/
public static void p(String s) {
JavaIO.dump(s);
}
/**
* creates a Prolog machine and runs on in a few queries
*/
public static void testJavaPrologInterface() {
Machine M=Top.new_machine();
{
// simple String queries
String s=M.run("member(X,[a,b,c])");
JavaIO.dump("testBinPrologJ: first X in member/3:
"+s);
M.run("assert(a(88))");
JavaIO.dump("assert works: " +
M.run("X:-a(X)"));
// building a compound term query, getting all
answers
Object X=new Var(1);
Object goal_args[]={X,new Integer(1),new Integer(5)};
Fun Goal=new Fun("for",goal_args);
Object[] answer_args={X,Goal};
Fun Query=new Fun(":-",answer_args);
if(!M.load_engine(Query)) return;
for(;;) {
Object answer=M.get_answer();
if(null==answer) {
// this kills the machine -
if still alive -
// it happens after last
answer automatically
M.stop();
break;
}
JavaIO.dump("testBinPrologJ: X in
for/3(X,1,5): "+answer);
}
}
{ // passing to Prolog a Java object for a call back method
M=Top.new_machine(); // stop killed the previous one
Date today=new Date();
Object R=new Var(1);
Object goal_args[]={today,"toString",R}; // note
first arg "today" - it is a handle to a Date
Fun Goal=new Fun("invoke_java_method",goal_args); //
we build the callback goal
Object[] answer_args={R,Goal}; // we build the
answer pattern to be returned
Fun Query=new Fun(":-",answer_args); // we put them
together as a query with clause syntax
if(!M.load_engine(Query)) return; // we load the
(existing) Prolog engine
for(;;) {
Object answer=M.get_answer(); // get an
answer
if(null==answer) {
M.stop();
break; // exit loop when
finished
}
// print out an answer
JavaIO.dump("testBinPrologJ: Prolog
callback
on a Java Date object gives ===> "+answer);
}
}
{ // some easier ways to build queries - using special purpose
Fun constructors
M=Top.new_machine(); // stop killed the previous one
Fun List=new Fun(".","a",new Fun(".","b","[]"));
Fun Goal=new Fun("append",new Var(1),new
Var(2),List); // we build the Prolog goal
Fun Query=new Fun(":-",new Fun("result",new
Var(1),new Var(2)),Goal); // we put them together as a query with
clause syntax
if(!M.load_engine(Query)) return; // we load the
(existing) Prolog engine
for(;;) {
Object answer=M.get_answer(); // get an
answer
if(null==answer) {
M.stop();
break; // exit loop when
finished
}
// print out an answer
JavaIO.dump("testBinPrologJ: Prolog
nondeterministic list append gives ===> "+answer);
}
}
}
/**
* Exhibits work in Java on a term sent from Prolog
*/
public static Object workOnPrologData(Object oterm) {
Machine machine=Top.new_machine();
p("TERM===> "+oterm);
Object O=((Fun)oterm).args[1];
p("CHOP===> "+O);
p("NODES===> "+countNodes(O));
p("LEAVES===> "+getLeaves(O));
Var X=new Var(1); Var Y=new Var(2);
Object[] args={
"hello",new Integer(11),
X,X,Y,Y,
new Double(3.14),
"bye"
};
return new Fun("fromJava",args);
}
/**
* simple recursive count node method
*/
static int countNodes(Object O) {
p("count_trace: "+O);
if(!(O instanceof Fun))
return 1;
Fun F=(Fun)O;
int count=1;
for(int i=0; i<F.args.length;
i++) {
count+=countNodes(F.args[i]);
}
return count;
}
/**
* collects leaves (Strings, ints etc.) of a Prolog term
seen as tree
*/
static Vector getLeaves(Object O) {
Vector V=new Vector();
try {
getLeaves(O,V);
}
catch(Exception e) {
JavaIO.errmes("error in getLeaves",e);
}
return V;
}
/**
* recurses over Prolog term seen as a tree
*/
static void getLeaves(Object O,Vector V) {
if(!(O instanceof Fun))
V.addElement(O);
else {
Fun F=(Fun)O;
for(int i=0; i<F.args.length; i++) {
getLeaves(F.args[i],V);
}
}
}
}
The Prolog side: file myMain.pl
test:-
new_java_class('MyMain',Class),
Term=f(X,g(3.14,hello,X,99),h(Y,Y)),
invoke_java_method(Class,workOnPrologData(Term),Result),
println(Result).
likes('Joe',beer).
likes('Mary',wine).
:-println('PLEASE TYPE test TO RUN THE OTHER
EXAMPLES').
Fluents
BinPrologJ can be seen as a collection of Prolog engines
working on a given compiled clause database and calling built-in
operations. Through built-in calls, they possess the ability to create
other query first class engines and interoperate with Java through a
set of stateful objects called Fluents.
Fluents are created with specific constructors or by converting from
other fluents or conventional Prolog data structures like Terms, Lists
or Databases. All Fluents are disabled with a stop/1
operation which releases their resources (most Fluents also
call stop/1 on backtracking to free resources).
Sources are Fluents enabled with an extra get/2
operation. Typical Sources are Horn Clause Engines, File, URL or String
Readers, Fluents built form Prolog lists. Sinks are
fluents enabled with an extra put/2 and collect/2 operation.Typical
fluents are ClauseWriters or CharWriters targeted to Files,
TermCollectors (implemented as a Java Vectors collecting Prolog
terms), StringSinks (implemented as a Java StringBuffers colecting
String representations of Prolog terms). Prolog Databases are first
class citizens implemented as extensions of Sources which provide add/2,
remove/2, collect/2 operations.
Fluents are resources which go throuh state transitions as a
result of put/2 or get/2 operations. They end
their life cycle in a stopped state when all the resources they hold
are freed. An algebra of Fluent composers provides abstract operations
on fluents. For instance, append_sources/3 creates a new Source
with a get/2 operation such that when the first Source is
stopped, iteration continues over the elements of the second
source. Compose_sources/3 provides a cartesian
product style composition, the new get/2 operation returning
pairs of elements of the first and second Source. Split_source/3
creates 2 Source objects identical to the Source given as first
argument. It allows writing programs which iterate over a given Source
multiple times. Sources and Sinks are related through a discharge(Source,Sink)operation
which sends all the elements of the Source to the given Sink.
Here is some Prolog code showing some fluent operations:
element_of(I,X):-get(I,the(A)),select_from(I,A,X).
select_from(_,A,A).
select_from(I,_,X):-element_of(I,X).
split_source(S,S1,S2):-
findall(NewS,nth_source_clone(2,S,NewS),[S1,S2]).
split_source(S,S1,S2,S3):-
findall(NewS,nth_source_clone(3,S,NewS),[S1,S2,S3]).
uniquify_source(S,SWithNoDups):-
findall(E,element_of(S,E),Es),
sort(Es,Sorted),
new_engine(X,member(X,Sorted),SWithNoDups).
nth_source_clone(N,S,NewS):-
findall(X,element_of(S,X),Xs),
for(_,1,N),
new_engine(X,member(X,Xs),NewS).
compose_sources(S1,S2,S):-new_engine(X,element_of_either(S1,S2,X),S).
element_of_either(S1,_,X):-element_of(S1,X).
element_of_either(_,S2,X):-element_of(S2,X).
File, socket, URL and string based I/O
BinPrologJ extends Prolog's file and stream I/O based operations to
URLs and
strings - to give a uniform view of all of them as streams% fluent
style readers.
Source Fluent based Input Stream constructors:
new_char_reader(Fname,Reader)
new_term_string_reader(Fname,Reader)
new_string_char_reader(String,Reader)
new_string_term_string_reader(String,Reader)
new_token_reader(Fname,Reader)
new_string_token_reader(String,Reader)
Reading a term from the standard input:
read_term(Term,VarsAndNames)
read(Term)
Reading from a string (Prolog atom)
sread(AtomString,TermAndVars): reads a term and vars from a string
sread_term(AtomString,Term)
sread_term(AtomString,Term,Vars)
sread_term(AtomString,Term,Vars,Names)
sread_clause(AtomString,clause(Clause,Vars,Names)
sread_clauses(S,C): read multiple clauses from a string
sread_terms(S,C): reads multiple terms from a string
sread_goal(AtomString,Term,NamesAndVars)
string_clause_reader(AtomString,ReaderStream)
get0(X): classic Prolog binary byte reader - returns a 0..255
integer code
get_code(X) - same as classic Prolog's get0(X)
get_char(C) - returns an atomic char
get(R) - returns an ascii code ignoring spaces
see(File): opens for reading
exists_file(F): checks if a file exists
find_file(File,NewFile): searches default directories and URLs for a
file and returns path+name
Prolog file input
pred_of(File,FN): extracts all predicate names F/N found in a Prolog
file or URL
clause_of(File,Clause): extracts all clauses from a Prolog file or
URL
clause_of(File,Clause,VarsAndNames): extracts all clauses from a
Prolog file or URL with Vars
term_of(F,C): extracts all clause terms from a Prolog file or URL
term_of(F,C,Vs): extracts all clause terms from a Prolog file or URL
and their Vars
term_string_of(F,S): extracts atom (Prolog string) representation of
terms in a Prolog file
url2tokens(URL,Tokens): extract a list if tokens from a file or URL
token_of(FileOrURL,Token): extracts and backtracks over tokens found
in a URL or file
url2codes(URL,Cs): reads a URL as lists of ascii codes
url2string(URL,S): reads a file or URL to a Prolog atom
file2string(F,S): reads a file or URL to a Prolog atom
char_of(URL,C): reads and backtracks over a URL or file returning
ascii codes
Prolog Output Operations
put_code(AsciiCodeOrByte): writes it to default output
put_char(Char): writes it to default output
write(Term): writes it to default output
print(Term): writes it to default output
writeq(Term): writes it to default output in a way it can be read back
write_unquoted(Term): writes it to default output
pp(Term): pretty prints a term or clause to default output
println(X): writes adding an end of line
ttynl: writes end of line to standard output
ttyput(AsciiCode): writes to standard output
ttyprint(Term): writes term to standard output
tell(File): sets File as default output device
tab(N): writes N spaces to default output device
Fluent Composers
Fluent composers provide abstract operations on Fluents. They are
usually implemented with lazy semantics.
For instance, append_sources/3 creates a new Source with a
get/2 operation such that when the first Source is stopped, iteration
continues over the elements of the second Source.
Compose_sources/3 provides a cartesian product style
composition, the new get/2 operation returning pairs of
elements of the first and second Source. Reverse_source/2
builds a new Source such that its get/2 method returns its
elements in reverse order.
Split_source/3 creates two Source objects identical to the
Source given as first argument. It allows writing programs which
iterate over a given Source multiple times. Sources and Sinks are
related through a discharge(Source,Sink) operation which sends all the
elements of the Source to the given Sink.
Fluent Modifiers (unimplemented)
Fluent modifiers allow dynamically changing some
attributes of a give Fluent. For instance set_persistent(Fluent,YesNo)
is used to make a Fluent survive failure, by disabling its undo
method, which, by default, applies the Fluent's stop method on
backtracking.
Engines as Source Fluents
Let us put to work in a more specific way the view of Interpreters
as Fluents. All we have to do, is provide is a Fluent constructor,
creating an Answer Source from an Answer Pattern and a Goal
given to an Interpreter. As a result, we will cover negation, limited
pruning through once/1, if-then-else/3, findall/3,var/1,
and, beyond standard Prolog, forms of lazy, on-demand generation of
sets of solutions, as well as a uniform set of built-ins for
manipulation of first class Prolog databases and external objects like
Files or URLs.
Answer Sources (engines) can be seen as generalized
iterators, allowing a given program to control answer production in
another. Each Answer Source works as a separate Prolog
interpreter.
The Answer Source constructor initializes a new interpreter.
new_engine(AnswerPattern,Goal,AnswerSource)
creates a new Horn Clause solver, uniquely identified by AnswerSource
(a Source Fluent), which shares code with the currently running program
and is initialized with resolvent Goal. AnswerPattern
is a term, usually a list of variables occurring in Goal.
The get/2 operation (provided by all Sources) is
used to retrieve successive answers generated by an Answer Source, on
demand.
get(AnswerSource,AnswerInstance)
tries to harvest the answer computed starting from Goal, as a
instance of AnswerPattern. If an answer is found it is returned
as the(AnswerInstance), otherwise no is returned. Note
that once no has been returned, all subsequent get/2 on
the same AnswerSource will return no. Bindings are not
propagated to the original Goal or AnswerPattern when get
retrieves an answer, i.e. AnswerInstance is obtained by first
standardizing apart (renaming) the variables in Goal and AnswerPattern,
and then backtracking over its alternative answers in a separate Prolog
interpreter. Therefore, backtracking in the caller interpreter does not
interfere with the new Answer Source's iteration over answers. Note
however that backtracking over the Answer Source's creation point as
such makes it unreachable and therefore subject to garbage collection.
Finally, an Answer Source is stopped with the stop/1
operation implemented by all Sources.
stop(AnswerSource)
The stop/1 operation is called automatically when no more
answers can be produced as well as through the Fluent's undo
operation on backtracking.
Note on BinPrologJ 's Syntax
BinPrologJ 's fast Java-based parser actually supports a set of
fixed operators,
matching something like 80-90% of those occurring in most Prolog
programs.
Unicode based language internationalization is supported by using
only the (wide) char type and appropriate JDK 1.x and later
reader and
writer classes. BinPrologJ 's parser and tokenizer are very small and
based on Java's own built-in parsing/tokenizing libraries
(StreamTokenizer). This allows relying on code already in
browsers instead of having to load classes over the network. In the
future, as BinPrologJ is heading towards plain Natural Language
input
through speech recognition software, it's internal syntax (which might
already look too restrictive to Prolog programmers) will be generated
through a preprocessor supporting user defined distfix operators. As
such, BinPrologJ is expected to be able to emulate full Prolog
syntax
and more. However, BinPrologJ 's current syntax is restricted to
standard prefix Prolog terms of the form f(T1,..Tn), with a number
of predefined prefix and infix operators. After parsing all
clause and expression level operators everything becomes a Prolog
Term - which can be described as follows:
Term
::
Const | VARIABLES | CompoundTerm
CommaSeparatedTerms ::
Term {,Term}*
CompoundTerm
::
IDENTIFIER(CommaSeperatedTerms)
Const
::
IDENTIFIER | INTEGER | REAL | SystemObject
IDENTIFIERs starting with lower case characters and containing only
alphabetical characters do not require quoting, for instance is(X,99)
is a valid term. When IDENTIFIERs start with upper case or contain
non-alphabetical characters they require single quotes, i.e. you should
write something like ':-'(a(X),b(X)) or
'+'(3,4). Variables start with upper case characters or
"_". Both % one line and /* ... */ multiple line comments are
supported.
BinPrologJ can also make use of the full
BinProlog parser, supporting full operator syntax. Type
?-full_parser(on).
?-full_parser(off).
to selectively turn it on and off.
Tracing and debugging
BinPrologJ provides tracing and debugging of both interpreted (dynamic)
and
compiled code through the use of a tracing metainterpreter. To start
tracing of interpreted code just type:
?-trace(Goal).
Compiled code needs to be loaded with a special command
?-debug(File).
After this, tracing works the same way as with interpreted code:
?- trace(nrev([1,2],Reversed)).
'Call: 'nrev([1,2],_133)
'Call: 'nrev([2],_466)
'Call: 'nrev('[]',_716)
'Exit: 'nrev('[]','[]')
'Call: 'app('[]',[2],_466)
'Exit: 'app('[]',[2],[2])
'Exit: 'nrev([2],[2])
'Call: 'app([2],[1],_133)
'Call: 'app('[]',[1],_1451)
'Exit: 'app('[]',[1],[1])
'Exit: 'app([2],[1],[2,1])
'Exit: 'nrev([1,2],[2,1])
Reversed = [2,1] ;
'Redo: 'nrev([1,2],[2,1])
'Redo: 'app([2],[1],[2,1])
'Redo: 'app('[]',[1],[1])
'Fail: 'app('[]',[1],_1451)
'Fail: 'app([2],[1],_133)
'Redo: 'nrev([2],[2])
'Redo: 'app('[]',[2],[2])
'Fail: 'app('[]',[2],_466)
'Redo: 'nrev('[]','[]')
'Fail: 'nrev('[]',_716)
'Fail: 'nrev([2],_466)
'Fail: 'nrev([1,2],_133)
no
BinPrologJ 's Prolog built-in predicates
BinPrologJ 's built-in predicates follow the spirit of Prolog while
simplifying when possible and adjusting to its restricted syntax. For
their complete executable specification and typical use cases we refer
to the file tarau/jinni/lib.pro containing the BinPrologJ system
library.
Basic built-ins of the compiler: covers a subset of BinProlog - an
Edinburgh style compiler close to ISO Prolog.
Note: unimplemented built-ins are
marked with ??? Currently some of the built-ins work only in the
compiled mode - the behavior is expected to become identical once the
interpreter/compiler merge is finished. Launch the interpreter with
ji.bat, launch the compiler with jc.bat
- !/0 : succeeds like true/0, but removes pending choices in
calls at its LEFT and makes things look as if this were the LAST clause
of the predicate
- * /3 : multiply
EXAMPLE(S):
?-*(10,3,A).
A = 30;
no
- (+)/3 : add
EXAMPLE(S):
?-+(10,3,A).
A = 13;
no
- (,)/2 : A,B succeeds if A suceeds and B, called after A,
succeeds
- (-)/1 : calls and possibly consumes assumed clause with
matching head
- (-)/3 : subtract
EXAMPLE(S):
?--(10,3,A).
A = 7;
no
- (->)/2 : Cond->Then executes Cond once; if it succeeds it
also executes Then
- / /3 : division
EXAMPLE(S):
?-/(10,3,A).
A = 3.33333;
no
- // /3 : integer division
EXAMPLE(S):
?-//(10,3,A).
A = 3;
no
- /\ /3 : bitwise AND
EXAMPLE(S):
?-/\(1,2,A).
A = 0;
no
- (;)/2 : A;B succeeds if A succeeds or B, called after A,
succeeds
- (<)/2 : numeric comparison
- << /3 : left shifts arg 1 by arg 2 bits
EXAMPLE(S):
?-<<(1,5,A).
A = 32;
no
- (=)/2 : (X,Y) true if terms X and Y unify - cyclic terms
can result from =/2, as occur check is not performed
EXAMPLE(S):
?-f(A,s(a)) = f(B,B).
A = s(a);
B = s(a);
no
- (=..)/2 : called univ -this is bidirectional- it converts
between a term and its view as a alist of components
EXAMPLE(S):
?-f(a,b) =.. A.
A = [f,a,b];
no
?-A =.. [f,a,b].
A = f(a,b);
no
- (=:=)/2 : numeric comparison
- (=<)/2 : numeric comparison
- (==)/2 : true if args are identical terms
- (=\=)/2 : numeric comparison
- (>)/2 : numeric comparison
- (>=)/2 : numeric comparison
- >> /3 : right shifts arg 1 by arg 2 bits
EXAMPLE(S):
?->>(16,2,A).
A = 4;
no
- (@<)/2 : instance of compare/3 with arg 1: <
- (@=<)/2 : instance of compare/3 with arg 1: = or <
- (@>)/2 : instance of compare/3 with arg 1: >
- (@>=)/2 : instance of compare/3 with arg 1: > or =
- 'C'/3 : DCG connect predicate
- \ /3 : bitwise complement
EXAMPLE(S):
?-\(0,2,A).
A = -3;
no
- (\+)/1 : succeeds if its argument is executed and fails
- \/ /3 : bitwise OR
EXAMPLE(S):
?-\/(1,2,A).
A = 3;
no
- (\=)/2 : true if args fail to unify
- (\==)/2 : true if arg 1 is not identical to arg 2
- ^ /2 : calls arg 2 and binds arg 1
EXAMPLE(S):
?-A^eq(A,1).
A = 1;
no
- abolish/1 : abolish(F/N) deletes predicate F/N
- abort/0 : returns to toplevel
- and/2 : conjunction, like comma
- append/3 : concatenates/decomposes lists
EXAMPLE(S):
?-append([1,2],[3,4],A).
A = [1,2,3,4];
no
?-append(A,B,[1,2]).
A = [];
B = [1,2];
A = [1];
B = [2];
A = [1,2];
B = [];
no
- arg/3 : arg(I,T,X) extracts arg I of term T to be unified with
X
EXAMPLE(S):
?-arg(2,f(a,b),A).
A = b;
no
- assert/1 : adds a clause
- asserta/1 : adds a clause to be first in a predicate definition
- assertz/1 : adds a clause to be last in a predicate definition
- atom/1 : true if symbol (functor of arity 0)
EXAMPLE(S):
?-atom(a).
yes
- atom_chars/2 : (Atom,CharAtoms): converts between an atom and its
list of char atoms representation
EXAMPLE(S):
?-atom_chars(hello,A).
A = [h,e,l,l,o];
no
?-atom_chars(A,[104,101,108,108,111]).
no
- atom_codes/2 : (Atom,CharCodes): converts between an atom and its
list of char code representation
EXAMPLE(S):
?-atom_codes(hello,A).
A = [104,101,108,108,111];
no
?-atom_codes(A,[104,101,108,108,111]).
A = hello;
no
- atomic/1 : true if an integer or symbolic constant
- bagof/3 : all solutions predicate generating unsorted bags of
possibly dupplicated answers
EXAMPLE(S):
?-bagof(A,member(A,[3,2,2,1]),B).
A = _x56274;
B = [3,2,2,1];
no
- bb_def/3 : bb_def(K1,K2,T) associates to K1 and K2 (a copy of) T
on the blackboard
- bb_let/3 : bb_let(K1,K2,T) updates or defines the term associated
with K1 and K2 to be T
- bb_rm/2 : removes the term associated with K1 and K2 from the
blackboard
- bb_set/3 : bb_set(K1,K2,T) updates the term associated with K1
and K2 to be a copy of T
- bb_val/3 : bb_val(K1,K2,T) T is (a copy of) the term associated
with keys K1 and K2
- bg/1 : runs Goal in background thread
- bg/2 : runs Goal in new background thread, which is returned
in second arg
- jboot/0 : regenerates file wam.bp in psrc directory (from
where it should be run)
- call/1 : executes (atomic!) arg 1
- call/2 : efficient call/N variant
- call/3 : efficient call/N variant
- call/4 : efficient call/N variant
- catch/3 : ISO Prolog exception operator: executes arg 1 and if
it catches arg 2, it executes arg 3
- clause/2 : clause(H,B) generates a clause with head matching H
and body B
- compare/3 : returns <,=,> in arg 1 after comparing arg 2
with arg 3
EXAMPLE(S):
?-compare(A,1,2).
A = (<);
no
?-compare(A,f(b),f(a)).
A = (>);
no
?-compare(A,s(B),s(B)).
A = (=);
B = _x56284;
no
- compile/1 : applies current compilation method to the file arg 1
- compound/1 : true if it has arity > 0
- EXAMPLE(S):
?-compound(f(a)).
yes
- consult/1 : consults with possible duplication of clauses, allows
later dynamic recompilation depending on db_ratio/1
- copy_term/2 : returns a copy of arg 1 with fresh variables
EXAMPLE(S):
?-copy_term(f(A,A,B,B),C).
A = _x56275;
B = _x56277;
C = f(_x56718,_x56718,_x56720,_x56720);
no
- new_engine/3 : new_engine(Answer,Goal,IntHandle) creates an engine
IntHandle
- get/2 : get(EngineOrFluent,Answer): gets an answer the(X) orno from an engine or other source fluent
- stop/1 : stops or closes engine or other fluent
- ctime/1 : gets elapsed cpu time in ms
EXAMPLE(S):
?-ctime(A).
A = 5247;
no
- get_db/1 : gets the name (a Java Object) of currently active
database
- current_thread/1 : gets thread id number of current thread
- db_abolish/2 : db_abolish(DB,F/N) removes predicate F/N from DB
- db_assert/2 : does assert/1 arg 2 into database given as arg 1
- db_asserta/2 : does asserta/1 arg 2 into database given as arg 1
- db_assertz/2 : does assertz/1 arg 2 into database given as arg 1
???
- db_clause/3 : clause(DB,H,B) generates a clause found in database DB
with head matching H and body B
- db_clean/0 : abolishes all predicates in currently active database
- db_clean/1 : db_clean(DB) abolishes all predicates in DB
- db_move/2 : db_move(FromDB,ToDB) moves the content of database
FromDB over database ToDB while replacing similar predicates
???
- db_retract/2 : does retract/1 arg 2 from database given as arg 1
- db_retract1/2 : deletes from database given as arg 1 a matching clause
- db_retractall/2 : removes from database given as arg 1, all matching
clauses
- db_save/1 : db_save(File) saves all the clauses of the current
database to File
- db_save/2, db_load/2, db_clean/2 :
db_save(Db,File) saves using
qprint/1 all the clauses of Db to File, db_load loads it, db_clean
resets it to empty
- display/1 : writes to terminal while ignoring operator definitions
- end_of_file/0 : Prolog atom returned by read when at the end of a file
- eq/2 : unifies arg 1 and arg 2, like =
- errmes/2 : writes error message and fails
- exists_file/1 : true if file exists
- return/1 : leaves current engine with arg 1 as returned value
instead of computed answer
- expand_term/2 : expands a term according to DCG expansion rules
- fail/0 : always fails
- findall/3 : findall(X,G,Xs) collects copies of all answers X of G
to Xs. If less then half of the heap is free, it allocates new engine
for running G
EXAMPLE(S):
?-findall(s(A),(member(A,[1,2,3]),A
> 1),B).
A = _x56278;
B = [s(2),s(3)];
no
- findall/4 : findall(X,G,Xs,Ys) appends the list of answers X of G
to Ys to obtain Xs
- EXAMPLE(S):
?-findall(s(A),(A = 1 ; A = 2),B,[3,4]).
A = _x56285;
B = [s(1),s(2),3,4];
no
- float/1 : true if represented as a 64 bit float number (C-double)
EXAMPLE(S):
?-float(3.14).
yes
- floor/2,ceiling/2,round/2 : float to int functions
EXAMPLE(S):
?-floor(1.3,A).
A = 1;
no
- foldl/4 : (Op,InitialValue,List,?Result) accumulates values
interating over List with binary Op
EXAMPLE(S):
?-foldl(+,0,[10,20,30],A).
A = 60;
no
- foldr/4 : (Op,InitialValue,List,?Result) accumulates values
interating over List with binary Op
EXAMPLE(S):
?-foldr(+,0,[10,20,30],A).
A = 60;
no
- for/3 : generates an integer in a range
EXAMPLE(S):
?-for(A,1,3).
A = 1;
A = 2;
A = 3;
no
- forall/2 : forall(A,B) for each answer returned by A computes and
igonres all answers comuted by B without any binding - used for its
side effects - (note: not expressed with the usual double negation
trick - this really makes sure all alternatives of A are
explored!)
- functor/3 : builds or decomposes a coumpound term
EXAMPLE(S):
?-functor(f(a,b),A,B).
A = f;
B = 2;
no
?-functor(A,f,3).
A = f(_x56878,_x56879,_x56880);
no
?-functor(f(a),f,1).
yes
- gensym/2 : generates a new name based on arg 1
- get/1 : inputs the next char code after skiping over white
space
- get0/1 : reads a char as an ascii code
- get_char/2 : (Stream,CharAsOneLetterConstant): inputs a char from a
stream -ISO Prolog ???
- get_code/1 : ISO char code reader ???
- get_code/2 : inputs a char code from a stream - ISO ???
- get_password/1 : gets default password for user ???
- ground/1 : true if arg has no free variables ???
EXAMPLE(S):
?-ground(f(a,b)).
yes
- halt/0 : stops Prolog
- if_any/3 : (Cond,Then,Else): executes Cond; each time when Cond
succeeds it also executes Then; if Cond never succeds it executes Else
- in/1 : waits to remove a term from Linda server
- integer/1 : true if an integer
- integer/2 : float to int cast ???
- interactive/1: toggles interactive query answering/tracing with arg 1
= yes or no
- (is)/2 : calls the function evaluator, mostly for arithmetics
EXAMPLE(S):
?-A is 3+4*2.
A = 11;
no
- is_builtin/1 : recognizes a predicate head as a builtin
EXAMPLE(S):
?-is_builtin(var(A)).
A = _x56271;
no
- is_compiled/1 : true if head of a compiled predicate
- is_dynamic/1: checks if dynamic
- is_prolog/1 : recognizes two modes jinni_compiled and
jinni_interpreted - useful for portability
- keysort/2 : sorts while grouping similar keys
EXAMPLE(S):
?-keysort([3-a,1-a,2-b,1-c,2-d],A).
A = [1-a,1-c,2-b,2-d,3-a];
no
- length/2 : generates/mesures length of a list
- listing/0 : lists current database
- listing/1 : lists given predicate if in current database
- listing/2 : lists predicate F of arity N if in current database
- log/2 : float function ???
- log/3 : returns log in base arg 1 of arg 2, a float ???
EXAMPLE(S):
?-log(2,8,A).
A = 3;
no
- login/1 : assumes default (nick)name for user ???
- main/0 : user defined optional startup predicate
- main/1 : default entry predicate
- map/3 : maps a predicate with 2 args to a list
EXAMPLE(S):
?-map(+1,[10,20],A).
A = [11,21];
no
- max/3 : (X,Y,Max): Max is the max of 2 numbers X, Y
- member/2 : (X,Xs): checks if an element X unifies with an element
on a list Xs or generates successively longer lists if Xs is unbound or
open ended
EXAMPLE(S):
?-member(2,[1,2]).
yes
?-member(A,[1,2]).
A = 1;
A = 2;
no
- merge_sort/3 : (Order,List,Sorted)
EXAMPLE(S):
?-merge_sort(>,[1,3,2,2,4],A).
A = [4,3,2,2,1];
no
- metacall/1 : calls the interpreter
- min/3 : (X,Y,Min): Min is the min of 2 numbers X, Y
- mod/3 : modulo
EXAMPLE(S):
?-mod(10,3,A).
A = 1;
no
- move/0 : first key Mobile Code operation: picks up wrapped
continuation and moves to remote site is there/0 has been set, or runs
it locally if here/0 has been set ???
- name/2 : bi-directional: converts atomic to/from list of chars
EXAMPLE(S):
?-name(hello,A).
A = [104,101,108,108,111];
no
?-name(A,[98,121,101]).
A = bye;
no
- namecat/4 : concatenates 3 names
EXAMPLE(S):
?-namecat(a,:,b,A).
A = a:b;
no
- new/2 : new(ClassFile,Instance): creates class instance using
code from file, i.e. new('progs/nrev',Instance)
- nl/0 : writes a new line character
- nonvar/1 : true if currently instantiated
- not/1 : negation as failure
- notify_about/1 : notifies a suspended matching
wait_for(Term,Contraint), if Constraint holds, that Term is available
- nth_member/3 : retrieves N-th element of a list
EXAMPLE(S):
?-nth_member(A,[a,b,c],B).
A = a;
B = 1;
A = b;
B = 2;
A = c;
B = 3;
no
- number/1 : true if integer or float
- number_chars/2 : (Number,CharAtoms): converts between a number and its
list of char atoms representation
EXAMPLE(S):
?-number_chars(1999,A).
A = [1,9,9,9];
no
- number_codes/2 : (Number,CharCodes): converts between a number and its
list of char code representation
EXAMPLE(S):
?-number_codes(1999,A).
A = [49,57,57,57];
no
?-number_codes(A,[50,48,48,49]).
A = 2001;
no
- numbervars/3 : binds to $VAR(I) with I over distinct integers
variables in a term
- out/1 : puts a term on Linda server or trigers resumption of a
matching in/1 waiting for this data
- password/1 : assumes default password for user ???
- phrase/2 : (Axiom, ?InputChars): DCG evaluator, starting from
Axiom, consuming/producing InputChars
- phrase/3 : (Axiom, ?InputChars, ?OutputChars): DCG evaluator,
staring from Axiom
EXAMPLE(S):
?-phrase(([a],[b]),[a,b|A],A).
A = _x56276;
no
- pow/3 : (Base,Expo,Val) computes power function
EXAMPLE(S):
?-pow(2,3,A).
A = 8;
no
- pp_clause/1 : prints out a clause with some care on how it looks
- println/1 : synchronized printing of a term on a line
- prod/2 : (List, ?Result): product of a list
EXAMPLE(S):
?-prod([10,20],A).
A = 200;
no
- put/1 : writes and ascii code as a char
EXAMPLE(S):
?-put(99).
c
yes
- put_char/2 : (Stream,CharAsOneLetterConstant): outputs a char to a
stream -ISO Prolog
- put_code/1 : ISO char code writer
EXAMPLE(S):
?-put_code(99).
c
yes
- put_code/2 : outputs a char code to a stream - ISO
- qprint/1 : prints out a clause such that a variant of it can
be always read back ???
- random/1 : returns a random integer
EXAMPLE(S):
?-random(A).
A = 3439;
no
- qcompile/1 : compiles quickly to memory
- rd/1 : reads a term matching arg 1 from Linda server
- read/1 : reads a term
- read_term/2 : reads a term and also a list of variable-name
associations
- sread/2 : reads a term from a constant
EXAMPLE(S):
?-sread(f(X,X,Y,Y),A).
A = f(_1,_1,_2,_2)-['X'=_1,'Y'=_2];
no
- reconsult/1 : reconsults a file to current database as interpreted
code, replaces duplicate predicate definitions already existing
- remote_run/1 : runs Goal on localhost Linda server using default
password
- remote_run/3 : (Answer,Goal,Result): runs Goal on loclhost server and
binds Answer with result
- remote_run/6 : (Host,Port,Answer,Goal,Password,Reply): if Password
matches password of the remote server, runs Goal there and returns
Reply from server
- repeat/0 : backtracks until its continuation succeeds; defined as
repeat. repeat:-repeat.
- restart/0 : cleans up data areas and reinitializes symbol tables
- retract/1 : backtracks over deleting matching clauses
- retract1/1 : deletes first matching clause in the current database
- retractall/1 : deletes all matching clauses
- return/1 : returns a value (arg 1) as answer of an engine
- return/0 : second key Mobile Code operation: forces the moved
continuation to come back and run left over goals ???
- round/2 : float to int function
???
EXAMPLE(S):
?-round(1.51,A).
A = 2;
no
- rtime/1 : gets elapsed real time in secs since start ???
EXAMPLE(S):
?-rtime(A).
A = 6;
no
- run_server/0 : runs foreground server on localhost, on a free port
- run_server/1 : runs foreground server on given or on free Port
- run_server/2: (Port,Passwd): runs server protected with Passwd
on Port - server will answer remote_run requests
- see_at/1 : seeks a seekable file at a give offset (in bytes)
???
- see_or_fail/1 : opens a file if it exists, otherwise fails
- seeing/1 : gets file name opened and set by see/1
- seeing_at/1 : retrieves position in current file opened by see/1 ???
- seen/0 : close file opened by see/1
- set_input/1 : sets current input stream ???
- setof/3 : all solutions predicate generating sorted sets of
unduplicated answers
EXAMPLE(S):
?-setof(A,member(A,[3,2,2,1]),B).
A = _x56274;
B = [1,2,3];
no
- sign/2 : int function ???
- sin/2 : float function
- sort/2 : sorts and removes duplicates -see also merge_sort/3-
EXAMPLE(S):
?-sort([2,1,3,1,4,4,2],A).
A = [1,2,3,4];
no
- spy/1 : set spy point on goal, triggering trace when
interpreted
- spying/1 : checks what we are spying
- sqrt/2 : returns square root of arg 1, a float ???
EXAMPLE(S):
?-sqrt(2,A).
A = 1.41421;
no
- sread/2 : reads a term from a string (atom) :
?-sread('f(X,Y)',A-B).
A = f(_x56645,_x56646);
B = ['X' = _x56645,'Y' = _x56646];
no
- stat/0 : short hand for statistics
- statistics/0 : shows info about data areas
EXAMPLE(S):
?-statistics.
runtime = [1191,1191]
global_stack = [199,824]
local_stack = [5,3]
trail = [7,1]
code = [12784,19984]
symbols = [552,0]
htable = [776,1272]
yes
- statistics/2 : returns info about data areas
- stop/0 : exits current engine
- stop/1 : stops and frees resources held by an engine or other
fluent (may happen automaticaly if an engine fails)
- sum/2 : (List,?Result): sum of a list
EXAMPLE(S):
?-sum([10,20],A).
A = 30;
no
- swrite/2 : writes a term to a string (atom)
- symcat/3 : makes new identifier from arg 1 and arg 2
EXAMPLE(S):
?-symcat(a,b,A).
A = a_b;
no
?-symcat(a,1,A).
A = a_1;
no
- system/1 : passes a command to the OS
- system/2 : passes a command to the OS and gets back return code
???
- tab/1 : outputs N blanks
- talk/0 : sends what you type in, to another
BinPrologJ
user ???
- tan/2 : float function
- tell/1 : focuses output on a file
- tell_at/1 : moves output file pointer to a given offset (in
bytes) ???
- tell_at_end/1 : focuses output on file opened in append mode
???
- telling/1 : gets file name opened and set by tell/1
- telling_at/1 : retrieves output file position (in bytes)
- term_append/3 : efficiently concatenates 2 terms
EXAMPLE(S):
?-term_append(f(a,b),g(c,d),A).
A = f(a,b,c,d);
no
- term_expansion/2 : can be used to define a hook into the default DCG
expansion mechanism
- term_hash/2 : computes hash code on main functor and functors of
arguments; fails if something is unbound ???
EXAMPLE(S):
?-term_hash(t(a,b),A).
A = 40050;
no
?-term_hash(t(a,c),A).
A = 40051;
no
- term_hash/3 : computes hash code based on main functor and
functors of listed argument positions; fails if something is unbound
???
EXAMPLE(S):
?-term_hash(t(a,b),[1,2],A).
A = 40050;
no
?-term_hash(t(a,c),[1,2],A).
A = 40051;
no
- this/1 : returns current object handle ???
- throw/1 : ISO Prolog exception operator: throws a term to be
caught by a matching catch
- told/0 : closes file opened by tell/1
- topcall/1 : calls arg 1 and signals uncaught exception thrown by
ISO Prolog built-in throw/3
- toplevel/0 : interactive toplevel Prolog loop
- true/0 : always succeeds
- truncate/2 : float to int function ???
EXAMPLE(S):
?-truncate(1.51,A).
A = 1;
no
- var/1 : true if currently an unbound variable
- wait_for/2 : wait_for(Term,Constraint) waits for a term on the
blackboard, such that Constraint hold
- write/1 : writes to current output stream set with tell/1,
defaults to Prolog's stdio
The BinPrologJ GUI
Visual BinPrologJ is a GUI library built through a set of
reflection,
engines, threads based Java and Prolog interaction. The Prolog
side works as a high-level visual scripting language on top of a
Personal Java (roughly jdk 1.1.8). As a result, it runns happily on
Java enabled PocketPCs lik Compaq's iPAQ with the Jeode Java
runtime. We will reproduce here the complete Prolog code - which is
self-explanatory - hoping that it gives an idea on the power and
flexibility of BinPrologJ's reflection based interface - and on putting
the
various capabilities of BinPrologJ together.
/*
Reflection based GUI
- the default AWT GUI can be overriden by an external Swing based
alternative Java implementation
- looking the same from Prolog, although the external GUI is
expected to
offer extra functionality with time
*/
/* builtin to Java connection tools - based on Reflection based
interface */
get_gui_class(CName):-get_global_prop(gui,swing),!,CName='jgui.Start'.
get_gui_class('prolog.core.GuiBuiltins').
call_gui_method(MethodAndArgs):-call_gui_method(MethodAndArgs,_).
call_gui_method(MethodAndArgs,Result):-
get_gui_class(CName),
call_java_class_method(
CName,
MethodAndArgs,
Result
).
/* builtins */
show(Container)
resize(Component,H,V)
move(Component,H,V)
/* creates a new frame - top window */
new_frame(Frame):
new_frame(Title,Frame):
new_frame(Title,Layout,Frame):
new_frame(Title,Layout,Kind,Frame):
new_panel(Parent,Layout,Panel):
new_label(Parent,Name,Label):
new_button(Parent,Name,Action,Button):
new_button(Parent,Name,Action,Output,Button):
set_label(Label,String):
new_file_dialog(Mode,Result):
new_text(Parent,Component):
new_text(Parent,String,Component):
new_text(Parent,String,Rows,Cols,Component):
set_text(Component,String):
% direct access to underlying TextSink - for visual displays only
set_text(String):
add_text(String):
get_text(String):
clear_text:
clear_text(Component):
% end of TextSink API
add_text(Component,String)
get_text(Component,String):
set_max_display(Max):
/* Colors */
new_color(R,G,B,Color):
make_white(Color):
make_blue(Color):
make_light_blue(Color):
make_gray(Color):
make_green(Color):
make_red(Color):
make_black(Color):
set_fg(Component,Color):
set_bg(Component,Color):
set_color(Component,Color):
/* Default Colors */
set_fg_color(R,G,B):
set_bg_color(R,G,B):
/* Default Fonts */
set_font_name(Name):
set_font_style(Style):
set_font_size(Size):
inc_font_size(Size):
to_default_font(Component):
remove_all(Container):
destroy(Component):
set_layout(Container,Layout):
/* used on Panels and Frames with border layout */
set_direction(Container,String):
/* Prolog IDE - contains simple editor and console */
ide:
ide(Name):
ide(Name,Query):
new_ide(Name):
new_ide(Container,Query):
new_ide(Container,Query,Output):
new_ide(Container,Query,Output,EditArea):
/* simple Prolog Console - reads, evaluates, prints answers */
console:
new_console:
new_console(Query):
new_console(Container,Query):
new_console(Container,Query,Output):
new_console(Container,Query,Rows,Cols, Output):
/* Prolog Dialog Box - implemented using Hubs - to synchronize consumer
and producer threads*/
dialog(Q,A):
dialog(Q,WhereX,WhereY,A):
dialog(Q,Y,N,WhereX,WhereY,SizeX,SizeY,A):
dialog_in(Parent,Q,A):
dialog_in(Parent,Q,Y,N,A):
/* reads a string from a new box - from which sread can be used
to extract Prolog terms */
gui_readln(StringRead):
/* Prolog Editor - squeeze to small default initial size size to
fit on PocketPCs - resize at will ! */
new_file_editor:
new_file_editor(Container,Editor):
The Prolog3D Java3D-based Agent-Oriented
3D-Animation
and 3D-Graph Layout API
This BinPrologJ extension requires
installing
the Java3D open source component, available as a Java extension module
from java.net. The API is Agent-Oriented - i.e. each
element of the 3D world is an agent implemented as an autnomous Java3D
behavior. The basic idea of this API is very simple: a Prolog
user can update/retrive the state of an agent at will. The Java3D
renderier will periodically revisit and render the current state of
each agents. Besides efficiency, this provides an interaction model
which can meke use of verious local and remote BinPrologJ resources
independly of the Java3D animation and geomtry rendering process.
From a Prolog user's perspective agent animation is achieved simply by
sending translation, rotation and scaling commands (or can be put on
autopilot). A combination of Java3D custom made shapes, loaded *.obj
models built with external tools and Prolog based planning or knowledge
processing allows a programmer to build complex 3D programs like games,
data visualisations, virtual reality applications etc.
As an application of the API we have developed an agent-based 3D layout
tool where vertices and edges are represented as agents driven by a
combination of spectral and force based layour algorithm. The layout
tool allows printing the resulting graphs and saving them as PNG
images. After the layout algorithm terminates, a compact "frozen graph"
representation is also provided that represents graphs containing
thousands of nodes as a single point/line geometry node.
% shows a Prolog3D canvas
show3d(RG):-show3d(RG,20,400,400,400).
%
shows a Prolog3D canvas for Timout msecs in a world
%
with given 3D radius and screen dimensions
show3d(RG,TimeOut,Radius,Width,Height):
%
creates a new 3D world in which various 3D agents are placed
new_world(U)
%
simple objects represented as agents
sphere(U,A)
point(U,A)
line(U,A)
tetra(U,A)
box(U,A)
color_cube(U,A)
pyram(U,A)
cone(U,A)
cylinder(U,A)
text2D(U,Text,A)
text3D(U,Text,A)
model3D(U,FileOrURL,A): imports Wavefront OBJ models as animated agents
%
creation of agents=object+behaviors
%
adds an agent with text content (i.e. 2D or 3D text)
add_agent(U,Shape,Text,A):
%
adds an agent of a given shape
add_agent(U,Shape,A):
%
adds randomly shaped/positioned agent
add_agent(U,A)
%
adds a vertex agent - to be positioned by a LayoutEngine
vertex_agent(U,L,V)
%
adds an edge agent - to be positioned by a LayoutEngine
edge_agent(U,From,To,Label,E)
%
adds an edge agent - represented as an animated object moving from
source to target
mobil_edge_agent(U,From,To,Label,E)
%
display the world in frame of given size
show_world(U,Width,Height)
%
displays a default size world
show_world(U):-show_world(U,400,400).
%
destroys world U
stop_world(U)
%
stops and discards an agent
stop_agent(A)
%
resets an agent in center of the world and default parameters
reset_agent(A)
%
makes an agent invisible
hide_agent(A)
%
makes an agent visible again
show_agent(A)
%
moves an agent A to coordinates X,Y,Z
move_to(A,X,Y,Z)
%
rotates an agent A using 3 Euler angles X,Y,Z
rotate_to(A,X,Y,Z)
%
scales an agent A uniformly to S
scale_to(A,S)
%
scales an agent by different rations on each coordinate
scale_to(A,X,Y,Z)
%
increment an agent's current postion by X,Y or Z
inc_x(A,X)
inc_y(A,Y)
inc_z(A,Z)
%
rotates an agent by a give Euler angle X,Y or Z
inc_rot_x(A,X)
inc_rot_y(A,Y)
inc_rot_z(A,Z)
%
sets the time after which the renderer will redisplay
%
changes made to the state of the agent
set_wake_up(A,Tick)
%
starts/stops autmatic random animation for agent A
auto(A,BoolString)
%
gets current X,Y or Z coordinate of an agent
get_x(A,R)
get_y(A,R)
get_z(A,R)
%
gets current X,Y or Z Euler angle rotation of an agent
get_rot_x(A,R)
get_rot_y(A,R)
get_rot_z(A,R)
%
gets current X,Y or Z scale factor of agent A
get_scale_x(A,R)
get_scale_y(A,R)
get_scale_z(A,R)
%
gets the complete translation/rotation/scale of an agent
get_agent_state(A,[pos(X,Y,Z),rot(RX,RY,RZ),scale(SX,SY,SZ)]):-
get_x(A,X),
get_y(A,Y),
get_z(A,Z),
get_rot_x(A,RX),
get_rot_y(A,RY),
get_rot_z(A,RZ),
get_scale_x(A,SX),
get_scale_y(A,SY),
get_scale_z(A,SZ).
%
returns a string rrepresentation of agent A
agent_to_string(A,S)
ViewPoint animation is supported by either setting the view directly or
by "attaching" the ViewPoint to any agent. As the agent moves, the
viewpoint is following it a proviedes a first person view centered on
the agent.
% sets the coordinates of the 'camera' the world is viewed
from
set_view(U,X,Y,Z):-
invoke_java_method(U,setView(X,Y,Z),_).
% sets a given agent as a 'holder' of the 'camera' that will follow its
transforms
set_holder(U,A):-
invoke_java_method(U,setHolder(A),_).
remove_holder(U):-
invoke_java_method(U,removeHolder,_).
Demos:
Type test3d to run a demo test suite
for Prolog3D.
Creating a set of animated agents in Prolog3D is very easy, as seen in
the following examples:
simple3d:-
N=6,
new_world(U),
findall(A,(
for(I,0,N),
add_agent(U,I,A),
Z
is -(1+I),inc_z(A,Z),
Y
is (I-N/2)/3,inc_y(A,Y)
),As),
show_world(U),
sleep(5),
foreach(member(A,As),auto(A,true)),
sleep(10),
foreach(member(A,As),stop_agent(A)),
stop_world(U).
other3d:-
N=3,Txt='Hello!',
new_world(U),
findall(A,(
for(I,0,N),
add_agent(U,I,Txt,A),
Z
is -(1+I),inc_z(A,Z),
Y
is (I-N/2)/3,inc_y(A,Y)
),As),
show_world(U),
sleep(10),
foreach(member(A,As),auto(A,true)),
sleep(10),
foreach(member(A,As),stop_agent(A)),
stop_world(U).
g31:-
new_world(U),
text3D(U,'Rotate me!',A),
show_world(U),
sleep(10),
stop_agent(A),
stop_world(U).
g32:-
new_world(U),
sphere(U,A),
show_world(U,240,320),
sleep(10),
stop_agent(A),
stop_world(U).
g33:-
new_world(U),
color_cube(U,A),
show_world(U),
sleep(5),
inc_z(A,-1),
set_wake_up(A,500),
(for(_I,1,10),
inc_rot_z(A,0.1),
inc_x(A,0.1),
get_agent_state(A,S),
println(state=S),
%
sleep(1),
fail
;true
),
(for(_I,1,10),
inc_rot_z(A,0.1),
inc_x(A,-0.1),
get_agent_state(A,S),
println(state=S),
%
sleep(1),
fail
;true
),
sleep(5),
auto(A,true),
sleep(10),
stop_agent(A),
stop_world(U).
g34:-
new_world(U),
text3D(U,'Hiding!',A),
inc_x(A,0.2),
show_world(U),
(for(_,1,3),
sleep(5),
println(hiding=A),
hide_agent(A),
sleep(5),
println(showing=A),
show_agent(A),
fail
; true
),
stop_agent(A),
stop_world(U).
% graph layout demos
gr1:-
new_world(U),
vertex_agent(U,hello,V1),move_to(V1,-0.5,0.5,-0.5),
vertex_agent(U,bye,V2),move_to(V2,0.5,0,-0.5),
edge_agent(U,V1,V2,bye,_E),
show_world(U),
sleep(10),
stop_world(U).
gr:-
random_ranked_graph(G,Info),
trim_ranked_graph(G,2,20,TG),
println(Info),
show3d(TG).
gr2:-
new_world(U),
gr2(U),
show_world(U),
sleep(15),
stop_world(U).
gr2(U):-
random_ranked_graph(G,Info),
println(Info),
findall(V-VA,(
vertex_of(G,V),
% vertex_data(G,V,VD),
VD=V,
vertex_agent(U,VD,VA),
auto(VA,true)
),
VAs),
member(V-VA,VAs),
outgoing_of(G,V,To),
member(To-ToA,VAs),
%edge_data(G,V,To,ED),
ED=e(from=V,to=To),
edge_agent(U,VA,ToA,ED,_EA),
fail.
gr2(_).
The BinPrologJ Google API adaptor
The adaptor (available as part of the BinNet Internet
Progrtamming Toolkit and theBinNet
Natural Language Processing Toolkit) allows building
BinPrologJ agents which can extract high level data in Prolog form by
using
the Google Web Services API (subject to obtain your own free 1000
hits/day Google search key code from them and download their last Java
based API adaptor).
?-
url_of('Free Lunch',URL).
URL = http://www.nofreelunch.org/
;
URL =
http://www.economy.com/freelunch/
;
URL =
http://www.freelunchdesign.com/
...
?-
snippet_of('Agent Programming with BinPrologJ',Answer).
Answer = 'Agent Programming Constructs and Object Oriented Logic
Programming in BinPrologJ .
The BinPrologJ Ontology: Orthogonal Language Constructs for Agent
Programming'
?- category_of('Agent
Programming',Answer).
Answer =
Top/Computers/Programming/Agents/Microsoft_Agent
?- title_of('Matrix
Reloaded',Answer).
Answer = The Matrix: Revolutions
;
Answer = Apple - Trailers -
Matrix Reloaded
;
Answer = The Editing Room - The
Matrix Reloaded: The Abridged Script
....
?-
summary_of('The Matrix Reloaded',Answer).
Answer = Official site for the
series. Cast and crew biographies, interviews,
ph otographs, production
notes,...
;
Answer = A short academic
analysis of religious allegories in the film.
...
The BinPrologJ SAX 2.0 based XML Processing
Component
Located in the jinni_xml sub-directory of the xjinni2k
component collection, the XML Processor contains the following:
Located in the jinni_xml sub-directory of the xjinni2k
component collection, the XML Processor contains the following:
- a BinPrologJ adaptor to the SAX 2.0 event based XML Parser
- a converter of Prolog terms to a reversible XML reprsentation
- a parser written in Prologfor converting back XML represented
terms
The BinPrologJ adaptor to the SAX 2.0 event based XML Parser
The SAX 2.0 parser coming with Sun's Java (1.4 or later) is event
based. As the parser walks through an XML file - a number of events are
generated. They are calls to a DefaultHandler instance that can be
overriden selectively by the application programmer. Instead of the
naive approach consisting off attaching these events to BinPrologJ
calls
resulting in side effects on the Prolog side we have set up a
producer-consumer mechanism which allows a BinPrologJ thread to collect
and
process XML events in a natural and (if the programmer prefers so)
completely side effect free style. Each class of BinPrologJ's handler
hierarchy implements the interface Runnable - as it will run on a
separate thread communicating with its Prolog peer. Our design is meant
to be easily extended both on the Prolog and the Java side. This
component comes in source form - to allow quick changes and fixes for
your application. If you wish, some of those changes and improvements
will be merged in our source code.
The class hierarchy is organized as follows:
Class Hierarchy
- class java.lang.Object
- class org.xml.sax.helpers.DefaultHandler
(implements org.xml.sax.ContentHandler, org.xml.sax.DTDHandler,
org.xml.sax.EntityResolver, org.xml.sax.ErrorHandler)
- class xml_converter.Main
- class xml_converter.XMLConverter
-
- FullXMLHandler
This class sends events to Prolog for each member of the
DefaultHandler SAX adaptor. It ensures that everything a programmer can
do in Java with these events can also be done in Prolog. It provides a
"complete" mapping from the set of events provided by the
DefaultHandler of the SAX parser to similarly named Prolog terms. Each
of the following methods is sent to Prolog as a term to be handled by xml_event_of(FileOrURL,Event)
which backtracks over the set of XML events resulting from calling the
SAX parser on a file or URL.
| Method Summary |
void |
characters(char[] buf,
int offset, int len)
Receive
notification of character data inside an element. |
void |
endDocument()
Receive
notification of the end of the document. |
void |
endElement(java.lang.String namespaceURI,
java.lang.String sName, java.lang.String qName)
Receive
notification of the end of an element. |
void |
endPrefixMapping(java.lang.String prefix)
|
void |
error(org.xml.sax.SAXParseException e)
|
void |
fatalError(org.xml.sax.SAXParseException e)
|
void |
ignorableWhitespace(char[] ch,
int start, int length)
|
void |
notationDecl(java.lang.String name,
java.lang.String publicId, java.lang.String systemId)
|
void |
processingInstruction(java.lang.String target,
java.lang.String data)
|
void |
setDocumentLocator(org.xml.sax.Locator locator)
|
void |
skippedEntity(java.lang.String name)
|
void |
startDocument()
Receive
notification of the start of the document. |
void |
startElement(java.lang.String namespaceURI,
java.lang.String sName, java.lang.String qName,
org.xml.sax.Attributes attrs)
|
void |
startPrefixMapping(java.lang.String prefix,
java.lang.String uri)
|
void |
unparsedEntityDecl(java.lang.String name,
java.lang.String publicId, java.lang.String systemId,
java.lang.String notationName)
|
void |
warning(org.xml.sax.SAXParseException e)
|
- GenericBinPrologJXMLHandler
This class acts as a no-action adaptor for various SAX Parser based
Handlers. While it actually calls the parser, it only sends end
of processing notification, needed to properly terminate the
Prolog side processing.
- SimpleXMLTermHandler and XMLTermHandler
These adaptors focus on XML represented handling Prolog terms. They
only override the (few) methods needed for the task. A quick look at prolog_data.xml,
which will be read in by xml2prolog_parser/2as a set of Prolog terms,
gives an idea on the structure of the XML data this class handles.
This root class creates a handler, based on a given input file or URL
and Hub. The hub receives SAX events converted to BinPrologJ's external
Prolog term representation. This is its PRODUCER side. A CONSUMER
Prolog thread pulls out these events as if they were "read" from a
stream.
The constructor:
XMLTermHandler(String infile,Hub hub) called from Prolog using BinPrologJ's reflection based Java interface
creates a handler, based on a given input file and Hub used to communicate with the Prolog side.
- XMLTermBuilder
-
- This adaptor focuses on XML represented handling Prolog terms.
This class builds, for faster processing - Prolog terms directly - the
work happens in Java. It really gives the illusion of having a DOM
parser. The complete "syntax tree" it builds is a (set of) Prolog
terms. The design can be extended to process other XML data which
requires "complete" processing in Java before data is passed to Prolog.
Prolog API
These Prolog predicates reflect the functionality of the previously
described Java classes. We will only provide a description of the most
important ones here. We refer the reader to xml_converter.pl -
where a few 2-3 line predicates describe this API in a self-documenting
way.
prolog2xml(PrologFileOrURL,XMLFile): Reflection based interface
for Prolog-to-XML converter. The converter takes a file or URL
containing Prolog clauses and builts an XML representation in another
file.
xml2prolog_parser(XMLFileorURL,Terms): Converter from XML
represented Prolog trees to Prolog terms - uses a DCG parser to
aggregate low level SAX parser events.
xml_event_of(FileOrURL,Event): backtracks over the set of XML
events resulting from calling the SAX parser on a file or URL.
xml_term_of(FileOrURL,Term): backtracks over the
set of XML represneted Prolog terms resulting from calling the SAX
parser on a file or URL containing such terms
You can use findall/3 to collect all events - or the get/2
a predicate of a new engine to explore the stream of events
produced by the last two predicates through a recursive loop.