A minimal Notation3 (N3) reasoner in JavaScript.
eyeling is:
eyeling.js, no external deps)=>) + backward (<=) chaining over Horn-style rulesTry it here:
The playground runs eyeling client-side. You can:
#...)This link preloads a small “Socrates is Mortal” ruleset:
BigInt support is fine)npm i eyeling
Run on a file:
npx eyeling examples/socrates.n3
(Or install globally: npm i -g eyeling and run eyeling ....)
const { reason } = require("eyeling");
const input = `
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#>.
@prefix : <http://example.org/socrates#>.
:Socrates a :Human.
:Human rdfs:subClassOf :Mortal.
{ ?S a ?A. ?A rdfs:subClassOf ?B } => { ?S a ?B }.
`;
const output = reason({ proofComments: false }, input);
console.log(output);
ESM:
import eyeling from "eyeling";
const output = eyeling.reason({ proofComments: false }, input);
console.log(output);
Note: the API currently shells out to the bundled eyeling.js CLI under the hood (simple + robust).
From a repo checkout:
npm test
Or run individual suites:
npm run test:api
npm run test:examples
npm run test:package
npm run test:packlist
test:api runs an independent JS API test suite (does not rely on examples/).test:examples runs the examples in the examples directory and compares against the golden outputs in examples/output.test:package does a “real consumer” smoke test: npm pack → install tarball into a temp project → run API + CLI + examples.test:packlist sanity-checks what will be published in the npm tarball (and the CLI shebang/bin wiring).From the repo root:
# Option 1: use the shebang (Unix-like)
./eyeling.js examples/socrates.n3
# Option 2: explicit node
node eyeling.js examples/socrates.n3
By default, eyeling:
# comments (can be disabled)node eyeling.js --version
node eyeling.js -v
# Disable proof comments (print only derived triples)
node eyeling.js --no-proof-comments examples/socrates.n3
node eyeling.js -n examples/socrates.n3
For each newly derived triple, eyeling prints:
-n), and thenThe proof comments are compact “local justifications” per derived triple (not a single exported global proof tree).
{ P } => { C } .{ H } <= { B } . and for built-ins.Forward rule premises are proved using:
The CLI prints only newly derived forward facts.
eyeling stays tiny, but includes a few key performance mechanisms:
Supported:
@prefix / @base; and ,?x[][ :p :o; :q :r ]( ... ){ ... }{ P } => { C } .{ H } <= { B } .^^"hello"@en, "colour"@en-GB"""...""" (can contain newlines; can also carry a language tag)?x <- :p ?y (swaps subject/object for that predicate)! and reverse ^): :joe!:hasAddress!:hasCity "Metropolis".# line commentsNon-goals / current limits:
eyeling follows the usual N3 intuition:
_:b1, _:b2, … within a run)_:sk_0, _:sk_1, …)Equal facts up to renaming of Skolem IDs are treated as duplicates and are not re-added.
eyeling understands the log:implies / log:impliedBy idiom.
Top level:
{ P } log:implies { C } . becomes a forward rule { P } => { C } .{ H } log:impliedBy { B } . becomes a backward rule { H } <= { B } .During reasoning:
log:implies / log:impliedBy triple with formula subject/object is turned into a new live forward/backward rule.{ ... } => false.Rules whose conclusion is false are treated as hard failures:
:stone :color :black .
:stone :color :white .
{ ?X :color :black . ?X :color :white . } => false.
As soon as the premise is provable, eyeling exits with status code 2.
eyeling implements a pragmatic subset of common N3 builtin families and evaluates them during backward goal proving:
crypto:md5 crypto:sha crypto:sha256 crypto:sha512list:append list:first list:firstRest list:in list:iterate list:last list:length list:map list:member list:memberAt list:notMember list:remove list:rest list:reverse list:sortlog:collectAllIn log:equalTo log:forAllIn log:impliedBy log:implies log:notEqualTo log:notIncludes log:skolem log:urimath:absoluteValue math:acos math:asin math:atan math:cos math:cosh math:degrees math:difference math:equalTo math:exponentiation math:greaterThan math:integerQuotient math:lessThan math:negation math:notEqualTo math:notGreaterThan math:notLessThan math:product math:quotient math:remainder math:rounded math:sin math:sinh math:sum math:tan math:tanhstring:concatenation string:contains string:containsIgnoringCase string:endsWith string:equalIgnoringCase string:format string:greaterThan string:jsonPointer string:lessThan string:matches string:notEqualIgnoringCase string:notGreaterThan string:notLessThan string:notMatches string:replace string:scrape string:startsWithtime:localTimeMIT (see LICENSE).