Rather than waiting for evaluation to finish and then inspecting a result set, aDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/HarvardPL/AbcDatalog/llms.txt
Use this file to discover all available pages before exploring further.
DatalogListener lets your application respond to new facts the moment they are derived. You associate a listener with a predicate symbol before evaluation starts; the executor then calls the listener’s method each time a new fact with that predicate is produced. This is the primary mechanism for building reactive logic on top of a running Datalog evaluation.
The DatalogListener interface
DatalogListener is a single-method interface:
DatalogListener has exactly one abstract method, you can supply any lambda or method reference wherever a DatalogListener is expected. The fact argument passed to newFactDerived is always a ground atom — fact.isGround() is guaranteed to be true.
Registering a listener
CallregisterListener(PredicateSym p, DatalogListener listener) on the executor after initialize() but before start():
- Must be called before
start(). CallingregisterListenerafter the evaluation has started throwsIllegalStateException. - Scoped to a predicate symbol. The listener fires only for facts whose predicate symbol matches
p. Facts with other predicates are not delivered to that listener. - Multiple listeners per predicate. You can register more than one listener for the same predicate symbol. Each registered listener will be invoked independently.
Example: two listeners from ExecutorExample
The following excerpt registers one listener to print every derived transitive-closure fact and a second listener to detect when a cycle is found:cycle predicate is zero-arity (cycle :- tc(X,X).), so its listener fires at most once — the moment the evaluator concludes that a cycle exists in the graph. The tc listener fires once per newly derived transitive-closure tuple.
Thread safety
Listeners are invoked in arbitrary threads managed by the executor. Two important consequences follow from this:- Do not block inside a listener. A blocking listener holds up the thread that called it, which can stall evaluation. Keep listener bodies short and non-blocking.
- Synchronize shared state. If a listener writes to a resource that might be accessed from multiple threads (such as the standard output stream or a shared collection), you must synchronize that access explicitly.
Collecting results from listeners
When you need to accumulate all facts that a listener receives, use a thread-safe collection.Collections.synchronizedSet or ConcurrentHashMap-backed sets are straightforward choices:
shutdown() completes if you need a consistent snapshot, since listeners may continue firing until shutdown finishes.