Prolog interop
@metta-ts/prolog lets a MeTTa program call a host Prolog runtime without changing the MeTTa evaluator. The package exposes PeTTa-compatible forms where they are independent of PeTTa's own Prolog evaluator: Predicate, callPredicate, assertzPredicate, retractPredicate, prolog-call, and import_prolog_function.
This is opt-in. A normal MeTTa run never loads Prolog. You choose a runtime adapter, register it, and run asynchronously.
Node with SWI-Prolog
Install the package and make sure swipl is on your PATH:
npm install @metta-ts/prologThen register the Node adapter:
import { MeTTa } from "@metta-ts/hyperon";
import { registerPrologInterop } from "@metta-ts/prolog";
import { swiPrologBridge } from "@metta-ts/prolog/swi-node";
const bridge = swiPrologBridge();
const metta = new MeTTa();
registerPrologInterop(metta, bridge);
const [results] = await metta.runAsync(`
!(assertzPredicate (Predicate (edge alice bob)))
!(prolog-call (edge alice $x))
`);
console.log(results.map((a) => a.toString())); // ["(edge alice bob)"]
await bridge.dispose();From the CLI, pass --prolog:
metta-ts --prolog program.mettaThe CLI wires .pl imports through the same host import hook:
!(import! &self "facts.pl")
!(prolog-call (edge alice $x))Browser with SWI-WASM
Use @metta-ts/prolog/swi-wasm when Prolog should run in the browser. The root package stays runtime-agnostic, and the WASM runtime is only pulled in when you import the SWI-WASM subpath.
import { createBrowserRunner, createBrowserTextLoader } from "@metta-ts/browser/host";
import { createSwiWasmInterop } from "@metta-ts/prolog/swi-wasm";
const files = new Map([["facts.pl", "edge(alice, bob).\nedge(alice, mars).\n"]]);
const loadText = createBrowserTextLoader({ files, baseUrl: import.meta.url });
const prolog = await createSwiWasmInterop({ loadText });
const runner = createBrowserRunner({ files, interops: [prolog] });
const results = await runner.run(`
!(import! &self "facts.pl")
!(prolog-call (edge alice $x))
`);
await runner.dispose();For interactive pages, run the browser runner and SWI-WASM inside a Web Worker. The main-thread adapter is fine for small examples, but Prolog startup and long queries can block rendering.
Predicate calls
prolog-call returns solved goals:
!(assertzPredicate (Predicate (edge alice bob)))
!(assertzPredicate (Predicate (edge alice mars)))
!(prolog-call (edge alice $x)) ; (edge alice bob), (edge alice mars)callPredicate is useful when you want a Boolean-shaped success test:
!(callPredicate (Predicate (edge alice $x))) ; True for each solutionimport_prolog_function turns a Prolog predicate whose last argument is the output into a MeTTa function:
!(import_prolog_function edge)
!(edge alice) ; bob, marsPeTTa compatibility boundary
The surface follows PeTTa where the operation is just a Prolog bridge. MeTTa TS does not switch into a PeTTa execution mode, does not add a curry mode, and does not compile all MeTTa rules to Prolog. Plain .pl imports, predicate calls, and function imports are host capabilities plugged into Hyperon-style evaluation.
To drive Python instead, see Python interop.