Skip to content

@mettascript/prolog

Optional Prolog interop for MeTTaScript. It gives a MeTTa program PeTTa-compatible predicate calls through a Prolog bridge that you provide. Use @mettascript/prolog/swi-node for a local swipl executable, or @mettascript/prolog/swi-wasm in the browser. A normal run never loads Prolog, and every Prolog operation is async.

bash
npm install @mettascript/prolog

For the browser adapter, install SWI-WASM beside it:

bash
npm install @mettascript/prolog swipl-wasm

Registering Prolog interop

ts
interface PrologBridge {
  query(goal: Atom): Promise<Atom[]>;
  asserta(term: Atom): Promise<void>;
  assertz(term: Atom): Promise<void>;
  retract(term: Atom): Promise<boolean>;
  consult(path: string): Promise<void>;
  predicateArities(name: string): Promise<number[]>;
  dispose(): Promise<void> | void;
}

interface PrologInteropOptions {
  readonly resolvePath?: (path: string) => string;
}

function registerPrologInterop(m: MeTTa, bridge: PrologBridge, opts?: PrologInteropOptions): void
function prologOps(bridge: PrologBridge, opts?: PrologInteropOptions): Map<string, (args: Atom[]) => Promise<PrologOperationReturn>>
function prologCoreAsyncOps(bridge: PrologBridge, opts?: PrologInteropOptions): Map<string, AsyncGroundFn>
const PROLOG_METTA_SRC: string
class MockPrologBridge implements PrologBridge

registerPrologInterop adds the async grounded operations to a MeTTa runner and loads PROLOG_METTA_SRC, which defines the MeTTa-side predicate helpers. prologOps gives the Hyperon-class operation map directly. prologCoreAsyncOps gives the same operations as core AsyncGroundFns for runProgramAsync or a CLI runner. resolvePath lets the host map a consulted path to a local or virtual file path. MockPrologBridge is an in-process bridge for tests and examples that should not start SWI-Prolog.

The package also exports the term codec and operation result types:

ts
type PrologTermJson =
  | { readonly type: "atom"; readonly name: string }
  | { readonly type: "int"; readonly value: string }
  | { readonly type: "float"; readonly value: number }
  | { readonly type: "string"; readonly value: string }
  | { readonly type: "var"; readonly name: string }
  | {
      readonly type: "compound";
      readonly functor: string;
      readonly args: readonly PrologTermJson[];
    };

function atomToPrologTerm(atom: Atom): PrologTermJson;
function prologTermToAtom(term: PrologTermJson): Atom;
type PrologEffect = AsyncOperationEffect;
type PrologOperationResult = AsyncOperationResult;
type PrologOperationReturn = AsyncOperationReturn;

atomToPrologTerm encodes symbols, variables, grounded numbers and strings, and expressions as Prolog JSON terms. prologTermToAtom decodes solved goals back into Hyperon atoms.

Runtime adapters

ts
// @mettascript/prolog/swi-node
interface SwiPrologBridgeOptions {
  readonly executable?: string;
}
class SwiPrologBridge implements PrologBridge
function swiPrologBridge(opts?: SwiPrologBridgeOptions): SwiPrologBridge

// @mettascript/prolog/swi-wasm
interface SwiWasmBridgeOptions {
  readonly loadText?: HostTextLoader;
  readonly baseUrl?: string | URL;
  readonly files?: ReadonlyMap<string, string>;
}
interface SwiWasmInteropOptions extends SwiWasmBridgeOptions {
  readonly prolog?: SwiWasmRuntime;
  readonly loadSwipl?: SwiWasmLoader;
  readonly locateFile?: (path: string, prefix?: string) => string;
  readonly arguments?: readonly string[];
  readonly preload?: readonly string[];
}
function swiWasmBridge(prolog: SwiWasmRuntime, options?: SwiWasmBridgeOptions): PrologBridge
function createSwiWasmInterop(options?: SwiWasmInteropOptions): Promise<HostInterop>

swiPrologBridge starts a small JSON server under swipl. swiWasmBridge wraps an already loaded SWI-WASM runtime. createSwiWasmInterop builds a browser HostInterop object for @mettascript/browser/host, including .pl file imports through the provided text loader.

MeTTa surface

formdoes
prolog-callqueries Prolog and returns each solved goal
prolog-matchqueries Prolog, binds the solved goal, then returns a template
Predicatewraps a goal for the PeTTa-compatible predicate helpers
callPredicatereturns True for each successful Prolog solution
assertaPredicate / assertzPredicateadds a fact or rule to the Prolog database
retractPredicateretracts the first matching Prolog fact or rule
prolog-consultconsults a Prolog source file
import_prolog_functionimports a predicate as a MeTTa function whose last Prolog argument is the result
import_prolog_functions_from_fileconsults a file, then imports named predicates as functions

Example

ts
import { 
MeTTa
} from "@mettascript/hyperon";
import {
registerPrologInterop
} from "@mettascript/prolog";
import {
swiPrologBridge
} from "@mettascript/prolog/swi-node";
const
bridge
=
swiPrologBridge
();
const
metta
= new
MeTTa
();
try {
registerPrologInterop
(
metta
,
bridge
);
const [,
results
] = await
metta
.
runAsync
(`
!(assertzPredicate (Predicate (edge alice bob))) !(prolog-call (edge alice $x)) `);
console
.
log
(
results
.
map
(
String
)); // ["(edge alice bob)"]
} finally { await
bridge
.
dispose
();
}

import_prolog_function is useful when the last Prolog argument is the value you want to return:

metta
!(assertzPredicate (Predicate (edge alice bob)))
!(import_prolog_function edge)
!(edge alice) ; bob

Released under the MIT License.