projog

7.1. Class Diagrams

Class Diagrams

Below are a series of class diagrams describing the architecture of the Projog project. The diagrams start with implementations of Term, the low-level building blocks used to construct Prolog clauses, and finishes with ProjogConsole, the console based application.

Terms

Terms are the building blocks used to construct Prolog programs and queries.

Implementations of the Term interface.
Implementations of the Term interface.

Prolog Syntax Parser

ProjogSourceReader populates a KnowledgeBase with clauses constructed by a SentenceParser from Prolog syntax contained in a text file.

SentenceParser transforms Prolog syntax into Term objects. SentenceParser can parse pre-, post- and in-fix operands e.g. "p([X|Y], Z) :- Z < X+1, p(Y, X).". SentenceParser uses TokenParser to retrieve Token objects representing individual numbers, predicate names and seperators, etc. TokenParser constructs the Token objects from characters read from CharacterParser.

CharacterParser uses a java.io.BufferedReader to read characters from a stream. CharacterParser keeps track of the current line and column number being parsed - this is useful for producing descriptive messages when an error occurs during parsing. Errors are propagated up using a ParserException - which takes a CharacterParser as a constructor argument.

Structure of the classes used to parse Prolog code.
Structure of the classes used to parse Prolog code.

Built-in Predicates

Projog provides a number of built-in predicates. Built-in predicates are functionality that is implemented in Java rather than constructed from Prolog code. Built-in predicates make it possible to provide a convenient and efficient way of doing standard tasks - including functionality that is not possible using only pure Prolog syntax. New built-in predicates can be easily developed by Java developers and "plugged-in" to Projog - obeying the open/closed principle. See Adding Extra Functionality to Prolog Using Java.

A projog-bootstrap.pl file, containing Prolog syntax, is used to initialise new Projog instances. This mechanism promotes flexibility as the configuration of built-in predicates can be controlled without altering any Java code.

User Defined Predicates

User defined predicates are generated at runtime as a result of parsing Prolog code. User defined predicates can be static or dynamic. Unlike static predicates, dynamic predicates can have clauses added or removed after they are first defined.

DynamicUserDefinedPredicateFactory is used to represent dynamic perdicates. StaticUserDefinedPredicateFactory is used to represent static perdicates. For performance reasons StaticUserDefinedPredicateFactory delegates to specialised implementations of PredicateFactory. If a user-defined predicate is suitable for term indexing (a similar concept to indexing of relational detabases) then IndexablePredicateFactory is used. If a user-defined predicate is tail-recursive then InterpretedTailRecursivePredicate is used.

Implementations of the UserDefinedPredicateFactory interface.
Implementations of the UserDefinedPredicateFactory interface.

Arithmetic Operators

Projog supports the common arithmetic operations. As with built-in predicates, new arithmetic operations can be easily developed by Java developers and "plugged-in" to Projog. See Adding New Arithmetic Operators to Prolog.

Implementations of the ArithmeticOperator interface.
Implementations of the ArithmeticOperator interface.

Knowledge Base

KnowledgeBase is the central object that connects the various components of an instance of the "core" inference engine.

The KnowledgeBase class and the components it is associated with.
The KnowledgeBase class and the components it is associated with.

Java API to Prolog inference engine

The Projog class provides a single high-level entry point for Java applications to interface with an instance of a Prolog inference engine. By shielding client code from the low-level implementation of the "core" inference engine Projog reduces coupling and makes the subsystem easier to use. (Example of the "facade" design pattern.)

The mechanism for evaluating Prolog queries is similar to Java's JDBC API used to query relational databases. QueryStatement is similar to java.sql.PreparedStatement. QueryResult is similar to java.sql.ResultSet. See Using Prolog in Java Applications.

The Projog API for calling Prolog from Java.
The Projog API for calling Prolog from Java.

Console Application

The ProjogConsole application allows Prolog developers to interact with the inference engine via a read-evaluate-print loop (REPL). ProjogConsole uses a Projog instance as a facade to the "core" inference engine. ProjogConsole registers a LoggingProjogListener so it can receive SpyPointEvent objects in order to provide feedback to the user.

Structure of the console based application.
Structure of the console based application.