eyeprolog 1.5.62 → 1.5.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -2
- package/examples/cross-organization-data-sharing.pl +1 -1
- package/examples/data/README.md +1 -1
- package/examples/data/symbiotic-knowledge-graph-rules.pl +3 -3
- package/examples/deck/introduction-to-eyeprolog.md +1 -1
- package/examples/deck/symbiotic-knowledge-graphs.md +6 -6
- package/examples/dpv-odrl-purpose-mapping.pl +2 -2
- package/examples/explainable-ev-depot-configuration.pl +1 -1
- package/examples/odrl-dpv-fpv-trust-flow.pl +2 -2
- package/examples/odrl-dpv-healthcare-risk-ranked.pl +2 -2
- package/examples/odrl-dpv-risk-ranked.pl +2 -2
- package/examples/odrl-policy-advanced.pl +2 -2
- package/examples/odrl-policy.pl +2 -2
- package/examples/operational-incident-response.pl +1 -1
- package/examples/output/symbiotic-knowledge-graph.pl +2 -2
- package/examples/rdf12-annotated-claims.pl +2 -2
- package/examples/rdf12-annotation.pl +2 -2
- package/examples/rdf12-directional-language.pl +2 -2
- package/examples/rdf12-nested-triple-term.pl +2 -2
- package/examples/rdf12-trig-graph-join.pl +2 -2
- package/examples/rdf12-trig-named-graph.pl +2 -2
- package/examples/rdf12-trig-triple-term.pl +2 -2
- package/examples/rdf12-triple-term.pl +2 -2
- package/examples/sbom-vulnerability-response.pl +1 -1
- package/examples/scientific-evidence-graph.pl +1 -1
- package/examples/symbiotic-knowledge-graph.pl +4 -4
- package/package.json +1 -1
- package/src/lib/error.pl +11 -8
- package/src/lib/si.pl +48 -10
- package/src/library-autoload-index.js +1 -0
- package/src/standard-library.js +1 -1
- package/test/regression/cases-api.mjs +2 -2
- package/test/regression/cases-documentation-sync.mjs +4 -4
- package/test/regression/cases-regression.mjs +76 -0
- package/the-art-of-eyeprolog.md +428 -424
- package/tools/generate-predicate-reference.mjs +1 -1
- package/tools/predicate-reference.json +10 -1
- package/why-eyeprolog.md +1 -1
package/README.md
CHANGED
|
@@ -69,14 +69,15 @@ printf 'human(socrates).\nmortal(X) :- human(X).\n' |
|
|
|
69
69
|
- [Example decks](examples/deck/README.md) — explainable RDF/Prolog scenarios with reproducible roundtrips
|
|
70
70
|
- [Introduction to EyeProlog](https://eyereasoner.github.io/eyeprolog/examples/deck/introduction-to-eyeprolog) — short presentation deck for first-time audiences
|
|
71
71
|
- [Symbiotic Knowledge Graphs](https://eyereasoner.github.io/eyeprolog/examples/deck/symbiotic-knowledge-graphs) — RDF ↔ Prolog heatwave-response demo for human/AI/KG co-evolution
|
|
72
|
-
- [rdf-prolog-
|
|
72
|
+
- [rdf-prolog-interchange](https://github.com/eyereasoner/rdf-prolog-interchange) — standalone RDF 1.2 ↔ ISO Prolog bridge used by the RDF examples
|
|
73
|
+
- [RDF and Prolog: Two Standards-Based Legs](https://github.com/eyereasoner/rdf-prolog-interchange/blob/main/why-rdf-prolog.md) — why W3C RDF and ISO Prolog form the foundation
|
|
73
74
|
- [ISO conformance review](test/conformance/ISO-COMPLIANCE.md) — supported Part 1 profile
|
|
74
75
|
- [Latest Neumerkel conformity](test/conformance/NEUMERKEL-LATEST.md) — tracked result from the current live upstream inventory
|
|
75
76
|
- [Conformance report](conformance-report.md) — generated executable conformance status, local corpus summary, and known deviations
|
|
76
77
|
- [OpenRuleBench](openrulebench/README.md) — portable benchmark profile
|
|
77
78
|
## RDF, Prolog, and symbiotic knowledge graphs
|
|
78
79
|
|
|
79
|
-
EyeProlog can sit behind an RDF knowledge graph without inventing a private graph representation. [`rdf-prolog-
|
|
80
|
+
EyeProlog can sit behind an RDF knowledge graph without inventing a private graph representation. [`rdf-prolog-interchange`](https://github.com/eyereasoner/rdf-prolog-interchange) converts RDF 1.2 datasets to ordinary `rdf(Subject, Predicate, Object, Graph)` facts, EyeProlog applies portable rules, and ground `rdf/4` results can be converted back to RDF.
|
|
80
81
|
|
|
81
82
|
The checked [Symbiotic Knowledge Graphs example](examples/symbiotic-knowledge-graph.pl) uses named graphs and RDF 1.2 triple terms to distinguish trusted knowledge, AI-proposed statements, and human review. Its [wide-audience companion](https://eyereasoner.github.io/eyeprolog/examples/deck/symbiotic-knowledge-graphs) explains why this is a useful present-day software model for human/AI/KG co-evolution: RDF supplies shared semantic memory, Prolog supplies explicit deliberation, AI supplies new hypotheses, and people remain participants in meaning and judgment.
|
|
82
83
|
|
package/examples/data/README.md
CHANGED
|
@@ -4,7 +4,7 @@ This directory contains source and materialized data that support runnable examp
|
|
|
4
4
|
|
|
5
5
|
## Symbiotic Knowledge Graphs
|
|
6
6
|
|
|
7
|
-
The heatwave-response example uses [`rdf-prolog-
|
|
7
|
+
The heatwave-response example uses [`rdf-prolog-interchange`](https://github.com/eyereasoner/rdf-prolog-interchange) as its RDF boundary:
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
10
|
symbiotic-knowledge-graph-input.nq
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
% Symbiotic knowledge graph rules for EyeProlog.
|
|
2
2
|
%
|
|
3
|
-
% The source rdf/4 facts above are generated by rdf-prolog-
|
|
3
|
+
% The source rdf/4 facts above are generated by rdf-prolog-interchange from
|
|
4
4
|
% symbiotic-knowledge-graph-input.nq. RDF stays the interchange and storage
|
|
5
5
|
% model; these rules provide the explicit reasoning and governance layer.
|
|
6
6
|
|
|
@@ -317,10 +317,10 @@ knowledge_exchange_fact(prolog_to_rdf, materialized_ground_rdf4).
|
|
|
317
317
|
|
|
318
318
|
pipeline_step(N, Description) :- pipeline_step_fact(N, Description).
|
|
319
319
|
pipeline_step_fact(1, 'RDF 1.2 N-Quads: named graphs keep source and governance boundaries explicit').
|
|
320
|
-
pipeline_step_fact(2, 'rdf-prolog-
|
|
320
|
+
pipeline_step_fact(2, 'rdf-prolog-interchange: RDF becomes ordinary rdf/4 Prolog facts without a solver').
|
|
321
321
|
pipeline_step_fact(3, 'EyeProlog: ISO Prolog rules validate candidates, apply review policy, and derive actions').
|
|
322
322
|
pipeline_step_fact(4, 'EyeProlog: result_rdf/4 materializes accepted knowledge and decisions as ground RDF-shaped facts').
|
|
323
|
-
pipeline_step_fact(5, 'rdf-prolog-
|
|
323
|
+
pipeline_step_fact(5, 'rdf-prolog-interchange: ground rdf/4 facts become RDF again for publication or federation').
|
|
324
324
|
|
|
325
325
|
cognitive_parallel(Prolog, Human) :- cognitive_parallel_fact(Prolog, Human).
|
|
326
326
|
cognitive_parallel_fact(fact, remembered_assertion).
|
|
@@ -166,7 +166,7 @@ Boolean constraints are compact when the domain is “on/off”, “selected/not
|
|
|
166
166
|
|
|
167
167
|
## RDF and knowledge graphs
|
|
168
168
|
|
|
169
|
-
EyeProlog pairs naturally with RDF through `rdf-prolog-
|
|
169
|
+
EyeProlog pairs naturally with RDF through `rdf-prolog-interchange`:
|
|
170
170
|
|
|
171
171
|
```text
|
|
172
172
|
RDF dataset
|
|
@@ -10,7 +10,7 @@ The demonstration does not claim that EyeProlog is a brain-computer interface. I
|
|
|
10
10
|
|
|
11
11
|
The architecture uses two small projects with deliberately separate jobs:
|
|
12
12
|
|
|
13
|
-
- [`rdf-prolog-
|
|
13
|
+
- [`rdf-prolog-interchange`](https://github.com/eyereasoner/rdf-prolog-interchange) moves RDF 1.2 datasets to and from ordinary `rdf/4` Prolog facts. It contains no Prolog solver.
|
|
14
14
|
- [EyeProlog](https://github.com/eyereasoner/eyeprolog) reasons over those facts with explicit ISO Prolog rules.
|
|
15
15
|
|
|
16
16
|
That separation is the central design choice. **RDF remains the shared interchange and publication layer; Prolog becomes the transparent reasoning layer.**
|
|
@@ -105,7 +105,7 @@ p2 confidencePercent 93
|
|
|
105
105
|
|
|
106
106
|
The embedded triple is a **statement being talked about**. It is not yet an asserted operational fact.
|
|
107
107
|
|
|
108
|
-
After `rdf-prolog-
|
|
108
|
+
After `rdf-prolog-interchange`, the same structure is an ordinary Prolog term:
|
|
109
109
|
|
|
110
110
|
```prolog
|
|
111
111
|
rdf(
|
|
@@ -246,10 +246,10 @@ That closeness makes it easier for a person to enter the machine's reasoning loo
|
|
|
246
246
|
|
|
247
247
|
Without RDF, the Prolog example could be dismissed as a hand-written toy knowledge base.
|
|
248
248
|
|
|
249
|
-
With `rdf-prolog-
|
|
249
|
+
With `rdf-prolog-interchange`, the roles are clearer:
|
|
250
250
|
|
|
251
251
|
- RDF provides Web identifiers, graph boundaries, literals, RDF 1.2 triple terms, and interoperable publication;
|
|
252
|
-
- `rdf-prolog-
|
|
252
|
+
- `rdf-prolog-interchange` preserves those structures as ordinary ISO Prolog terms;
|
|
253
253
|
- EyeProlog applies explicit rules and explores alternatives;
|
|
254
254
|
- materialized conclusions return to RDF.
|
|
255
255
|
|
|
@@ -279,7 +279,7 @@ A direct neural interface would change the input/output channel. It would not re
|
|
|
279
279
|
|
|
280
280
|
## Reproduce the roundtrip
|
|
281
281
|
|
|
282
|
-
Assuming `rdf-prolog-
|
|
282
|
+
Assuming `rdf-prolog-interchange` and EyeProlog are available on `PATH`:
|
|
283
283
|
|
|
284
284
|
```sh
|
|
285
285
|
rdf-to-prolog \
|
|
@@ -327,5 +327,5 @@ The deepest reason Prolog fits this vision is not nostalgia or syntax. It is tha
|
|
|
327
327
|
## References
|
|
328
328
|
|
|
329
329
|
- Ruben Taelman, [*Symbiotic Knowledge Graphs: A Vision for Semantic Brain-Computer Interfaces*](https://rubensworks.github.io/article-iswc2026-vision-symbiotic-knowledge-graphs/).
|
|
330
|
-
- [`eyereasoner/rdf-prolog-
|
|
330
|
+
- [`eyereasoner/rdf-prolog-interchange`](https://github.com/eyereasoner/rdf-prolog-interchange) — standalone RDF 1.2 ↔ ISO Prolog roundtripping toolkit.
|
|
331
331
|
- [`eyereasoner/eyeprolog`](https://github.com/eyereasoner/eyeprolog) — ISO Prolog reasoning and proof engine.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
package/examples/odrl-policy.pl
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -29,10 +29,10 @@ knowledge_exchange(machine_to_human, recommendation(after_review, riverside, ope
|
|
|
29
29
|
knowledge_exchange(rdf_to_prolog, ordinary_rdf4_facts).
|
|
30
30
|
knowledge_exchange(prolog_to_rdf, materialized_ground_rdf4).
|
|
31
31
|
pipeline_step(1, 'RDF 1.2 N-Quads: named graphs keep source and governance boundaries explicit').
|
|
32
|
-
pipeline_step(2, 'rdf-prolog-
|
|
32
|
+
pipeline_step(2, 'rdf-prolog-interchange: RDF becomes ordinary rdf/4 Prolog facts without a solver').
|
|
33
33
|
pipeline_step(3, 'EyeProlog: ISO Prolog rules validate candidates, apply review policy, and derive actions').
|
|
34
34
|
pipeline_step(4, 'EyeProlog: result_rdf/4 materializes accepted knowledge and decisions as ground RDF-shaped facts').
|
|
35
|
-
pipeline_step(5, 'rdf-prolog-
|
|
35
|
+
pipeline_step(5, 'rdf-prolog-interchange: ground rdf/4 facts become RDF again for publication or federation').
|
|
36
36
|
cognitive_parallel(fact, remembered_assertion).
|
|
37
37
|
cognitive_parallel(rule, reusable_generalization).
|
|
38
38
|
cognitive_parallel(query, explicit_question).
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
% Adapted from rdf-prolog-
|
|
1
|
+
% Adapted from rdf-prolog-interchange.
|
|
2
2
|
% This standalone program combines generated RDF input with its ISO Prolog rules.
|
|
3
3
|
|
|
4
|
-
% Generated by rdf-prolog-
|
|
4
|
+
% Generated by rdf-prolog-interchange.
|
|
5
5
|
|
|
6
6
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
7
7
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
% Generated by rdf-prolog-
|
|
1
|
+
% Generated by rdf-prolog-interchange.
|
|
2
2
|
|
|
3
3
|
% RDF terms use rdf(Subject, Predicate, Object, Graph).
|
|
4
4
|
|
|
@@ -63,7 +63,7 @@ rdf(iri('https://example.org/city/review/r3'), iri('https://example.org/vocab/no
|
|
|
63
63
|
% Rules
|
|
64
64
|
% Symbiotic knowledge graph rules for EyeProlog.
|
|
65
65
|
%
|
|
66
|
-
% The source rdf/4 facts above are generated by rdf-prolog-
|
|
66
|
+
% The source rdf/4 facts above are generated by rdf-prolog-interchange from
|
|
67
67
|
% symbiotic-knowledge-graph-input.nq. RDF stays the interchange and storage
|
|
68
68
|
% model; these rules provide the explicit reasoning and governance layer.
|
|
69
69
|
|
|
@@ -380,10 +380,10 @@ knowledge_exchange_fact(prolog_to_rdf, materialized_ground_rdf4).
|
|
|
380
380
|
|
|
381
381
|
pipeline_step(N, Description) :- pipeline_step_fact(N, Description).
|
|
382
382
|
pipeline_step_fact(1, 'RDF 1.2 N-Quads: named graphs keep source and governance boundaries explicit').
|
|
383
|
-
pipeline_step_fact(2, 'rdf-prolog-
|
|
383
|
+
pipeline_step_fact(2, 'rdf-prolog-interchange: RDF becomes ordinary rdf/4 Prolog facts without a solver').
|
|
384
384
|
pipeline_step_fact(3, 'EyeProlog: ISO Prolog rules validate candidates, apply review policy, and derive actions').
|
|
385
385
|
pipeline_step_fact(4, 'EyeProlog: result_rdf/4 materializes accepted knowledge and decisions as ground RDF-shaped facts').
|
|
386
|
-
pipeline_step_fact(5, 'rdf-prolog-
|
|
386
|
+
pipeline_step_fact(5, 'rdf-prolog-interchange: ground rdf/4 facts become RDF again for publication or federation').
|
|
387
387
|
|
|
388
388
|
cognitive_parallel(Prolog, Human) :- cognitive_parallel_fact(Prolog, Human).
|
|
389
389
|
cognitive_parallel_fact(fact, remembered_assertion).
|
package/package.json
CHANGED
package/src/lib/error.pl
CHANGED
|
@@ -143,12 +143,15 @@ call_with_error_context(Goal, Pair) :-
|
|
|
143
143
|
( copy_term(Pair, Element),
|
|
144
144
|
throw(error(Error, [Element|Context])) )).
|
|
145
145
|
|
|
146
|
-
% The element must be a pair (issue #99).
|
|
147
|
-
% must_be
|
|
148
|
-
%
|
|
149
|
-
%
|
|
146
|
+
% The element must be a pair (issue #99). The test is inlined rather than
|
|
147
|
+
% delegated to must_be(pair, _) so that the wrapper stays independent of the
|
|
148
|
+
% rest of this module. The reported context matches what must_be(pair, _)
|
|
149
|
+
% produces.
|
|
150
|
+
% Written as indexed clauses rather than an if-then-else: this runs on every
|
|
151
|
+
% call_with_error_context/2 call, and an if-then-else costs several times what
|
|
152
|
+
% first-argument clause selection does.
|
|
153
|
+
error__require_pair(Pair) :- var(Pair), !,
|
|
154
|
+
throw(error(instantiation_error, [predicate-must_be/2])).
|
|
155
|
+
error__require_pair(_-_) :- !.
|
|
150
156
|
error__require_pair(Pair) :-
|
|
151
|
-
|
|
152
|
-
; Pair = _-_ -> true
|
|
153
|
-
; throw(error(type_error(pair, Pair), [predicate-must_be/2]))
|
|
154
|
-
).
|
|
157
|
+
throw(error(type_error(pair, Pair), [predicate-must_be/2])).
|
package/src/lib/si.pl
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
character_si/1,
|
|
9
9
|
term_si/1,
|
|
10
10
|
chars_si/1,
|
|
11
|
+
compare_si/3,
|
|
11
12
|
dif_si/2,
|
|
12
13
|
not_si/1,
|
|
13
14
|
when_si/2
|
|
@@ -16,24 +17,24 @@
|
|
|
16
17
|
:- meta_predicate(not_si(0)).
|
|
17
18
|
:- meta_predicate(when_si(+, 0)).
|
|
18
19
|
|
|
19
|
-
atom_si(A) :- ( var(A) -> throw(error(instantiation_error, atom_si/1)) ; atom(A) ).
|
|
20
|
-
integer_si(I) :- ( var(I) -> throw(error(instantiation_error, integer_si/1)) ; integer(I) ).
|
|
21
|
-
atomic_si(A) :- ( var(A) -> throw(error(instantiation_error, atomic_si/1)) ; atomic(A) ).
|
|
20
|
+
atom_si(A) :- ( var(A) -> throw(error(instantiation_error, [predicate-atom_si/1])) ; atom(A) ).
|
|
21
|
+
integer_si(I) :- ( var(I) -> throw(error(instantiation_error, [predicate-integer_si/1])) ; integer(I) ).
|
|
22
|
+
atomic_si(A) :- ( var(A) -> throw(error(instantiation_error, [predicate-atomic_si/1])) ; atomic(A) ).
|
|
22
23
|
|
|
23
24
|
list_si(List) :- si__list(List).
|
|
25
|
+
si__list(Term) :-
|
|
26
|
+
var(Term), !, throw(error(instantiation_error, [predicate-list_si/1])).
|
|
24
27
|
si__list([]).
|
|
25
28
|
si__list([_|Tail]) :- !, si__list(Tail).
|
|
26
|
-
si__list(Term) :-
|
|
27
|
-
( var(Term) -> throw(error(instantiation_error, list_si/1)) ; fail ).
|
|
28
29
|
|
|
29
30
|
character_si(C) :-
|
|
30
|
-
( var(C) -> throw(error(instantiation_error, character_si/1))
|
|
31
|
+
( var(C) -> throw(error(instantiation_error, [predicate-character_si/1]))
|
|
31
32
|
; atom(C), atom_length(C, 1)
|
|
32
33
|
).
|
|
33
34
|
|
|
34
35
|
term_si(Term) :-
|
|
35
36
|
( ground(Term) -> acyclic_term(Term)
|
|
36
|
-
; throw(error(instantiation_error, term_si/1))
|
|
37
|
+
; throw(error(instantiation_error, [predicate-term_si/1]))
|
|
37
38
|
).
|
|
38
39
|
|
|
39
40
|
chars_si(Chars) :-
|
|
@@ -44,19 +45,56 @@ si__chars([C|Cs]) :- character_si(C), si__chars(Cs).
|
|
|
44
45
|
|
|
45
46
|
dif_si(X, Y) :-
|
|
46
47
|
X \== Y,
|
|
47
|
-
( X \= Y -> true ; throw(error(instantiation_error, dif_si/2)) ).
|
|
48
|
+
( X \= Y -> true ; throw(error(instantiation_error, [predicate-dif_si/2])) ).
|
|
48
49
|
|
|
49
50
|
not_si(Goal) :- term_si(Goal), \+ Goal.
|
|
50
51
|
|
|
51
52
|
when_si(Condition, Goal) :-
|
|
52
53
|
( si__condition(Condition) ->
|
|
53
54
|
( call(Condition) -> call(Goal)
|
|
54
|
-
; throw(error(instantiation_error, when_si/2)) )
|
|
55
|
+
; throw(error(instantiation_error, [predicate-when_si/2])) )
|
|
55
56
|
; throw(error(domain_error(when_condition_si, Condition), when_si/2))
|
|
56
57
|
).
|
|
57
58
|
|
|
58
|
-
si__condition(Condition) :- var(Condition), !, throw(error(instantiation_error, when_si/2)).
|
|
59
|
+
si__condition(Condition) :- var(Condition), !, throw(error(instantiation_error, [predicate-when_si/2])).
|
|
59
60
|
si__condition(ground(_)).
|
|
60
61
|
si__condition(nonvar(_)).
|
|
61
62
|
si__condition((A,B)) :- si__condition(A), si__condition(B).
|
|
62
63
|
si__condition((A;B)) :- si__condition(A), si__condition(B).
|
|
64
|
+
|
|
65
|
+
% compare_si(Order, A, B) holds when compare(Order, A, B) holds for *every*
|
|
66
|
+
% instance of A and B, and raises an instantiation_error otherwise. The point
|
|
67
|
+
% is to raise it as rarely as possible: an unbound variable only matters when
|
|
68
|
+
% it is what decides the ordering. So f(X) @< g(Y) is decided by the functor
|
|
69
|
+
% names, f(X,a) @< f(X,b) by the second arguments, and X == X gives (=), while
|
|
70
|
+
% f(a) vs f(Y) and X vs 1 are genuinely undecided.
|
|
71
|
+
compare_si(Order, A, B) :-
|
|
72
|
+
( A == B
|
|
73
|
+
-> Order = (=)
|
|
74
|
+
; si__order_decided(A, B)
|
|
75
|
+
-> compare(Order, A, B)
|
|
76
|
+
; throw(error(instantiation_error, [predicate-compare_si/3]))
|
|
77
|
+
).
|
|
78
|
+
|
|
79
|
+
% Both arguments are known to be non-identical here.
|
|
80
|
+
si__order_decided(A, B) :- ( var(A) ; var(B) ), !, fail.
|
|
81
|
+
si__order_decided(A, B) :-
|
|
82
|
+
compound(A), compound(B), !,
|
|
83
|
+
functor(A, NameA, ArityA),
|
|
84
|
+
functor(B, NameB, ArityB),
|
|
85
|
+
( ArityA =\= ArityB -> true
|
|
86
|
+
; NameA \== NameB -> true
|
|
87
|
+
; A =.. [_|ArgsA],
|
|
88
|
+
B =.. [_|ArgsB],
|
|
89
|
+
si__args_decided(ArgsA, ArgsB)
|
|
90
|
+
).
|
|
91
|
+
% Otherwise both are non-variables and at least one is atomic, so either the
|
|
92
|
+
% type order or the values themselves settle it and no instantiation can
|
|
93
|
+
% change the outcome.
|
|
94
|
+
si__order_decided(_, _).
|
|
95
|
+
|
|
96
|
+
si__args_decided([A|As], [B|Bs]) :-
|
|
97
|
+
( A == B
|
|
98
|
+
-> si__args_decided(As, Bs)
|
|
99
|
+
; si__order_decided(A, B)
|
|
100
|
+
).
|
package/src/standard-library.js
CHANGED
|
@@ -178,7 +178,7 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
|
|
|
178
178
|
',/3', ';/3', '=/3', 'cond_t/3', 'dif/3', 'if_/3', 'memberd_t/3',
|
|
179
179
|
'tfilter/3', 'tmember/2', 'tmember_t/3', 'tpartition/4',
|
|
180
180
|
'atom_si/1', 'integer_si/1', 'atomic_si/1', 'list_si/1', 'character_si/1',
|
|
181
|
-
'term_si/1', 'chars_si/1', 'dif_si/2', 'not_si/1', 'when_si/2',
|
|
181
|
+
'term_si/1', 'chars_si/1', 'compare_si/3', 'dif_si/2', 'not_si/1', 'when_si/2',
|
|
182
182
|
'matches/3', 'split/3', 'replace/4', 'lowercase/2', 'uppercase/2', 'trim/2',
|
|
183
183
|
'number_string/2', 'atom_string/2', 'term_string/2', 'string_concat/3',
|
|
184
184
|
'contains/2', 'matches/2', 'join/3', 'substring/4',
|
|
@@ -1331,7 +1331,7 @@ answer(ok) :-
|
|
|
1331
1331
|
assertEqual(registry.get('setup_call_cleanup', 3), null, 'setup_call_cleanup/3 is absent from the ISO registry');
|
|
1332
1332
|
assertEqual(Boolean(library.get('setup_call_cleanup', 3)), true, 'setup_call_cleanup/3 is an EyeProlog cleanup control');
|
|
1333
1333
|
assertEqual(registeredNativeEyePrologLibraryNames().length, 122, 'public host-supported EyeProlog library count');
|
|
1334
|
-
assertEqual(eyePrologPortableLibraryIndicators.length,
|
|
1334
|
+
assertEqual(eyePrologPortableLibraryIndicators.length, 282, 'portable Prolog library count');
|
|
1335
1335
|
assertEqual(eyePrologInteropLibraryIndicators.length, 221, 'cross-implementation interop profile count');
|
|
1336
1336
|
assertEqual(eyePrologInteropLibraryModules.length, 27, 'common explicit library module profile count');
|
|
1337
1337
|
assertEqual(eyePrologInteropAutoload['member/2'], 'lists', 'member/2 canonical autoload');
|
|
@@ -1349,7 +1349,7 @@ answer(ok) :-
|
|
|
1349
1349
|
assertEqual(eyePrologNativeLibraryIndicators.length, 122, 'host-supported library count');
|
|
1350
1350
|
assertEqual(eyePrologNativeLibraryIndicators.includes('call_nth/2'), true, 'call_nth/2 remains classified as host-supported');
|
|
1351
1351
|
assertEqual(eyePrologNativeLibraryIndicators.includes('random/1'), true, 'stateful random/1 is classified as host-supported');
|
|
1352
|
-
assertEqual(eyePrologLibraryIndicators.length,
|
|
1352
|
+
assertEqual(eyePrologLibraryIndicators.length, 404, 'complete non-ISO EyeProlog library surface');
|
|
1353
1353
|
assertEqual(registry.get('eyeprolog__call_nth', 2), null, 'private call_nth adapter is absent from ISO registry');
|
|
1354
1354
|
assertEqual(Boolean(library.get('eyeprolog__call_nth', 2)), true, 'private call_nth adapter is registered for EyeProlog');
|
|
1355
1355
|
assertEqual(Boolean(library.get('eyeprolog__call_residue_vars', 2)), true, 'private call_residue_vars adapter is registered for EyeProlog');
|
|
@@ -61,15 +61,15 @@ export function documentationSyncCases() {
|
|
|
61
61
|
encoding: 'utf8',
|
|
62
62
|
});
|
|
63
63
|
assertEqual(result.status, 0, 'exit status');
|
|
64
|
-
assertIncludes(result.stdout, 'predicate reference is up to date (
|
|
64
|
+
assertIncludes(result.stdout, 'predicate reference is up to date (533 predicates)', 'stdout');
|
|
65
65
|
assertEqual(result.stderr, '', 'stderr');
|
|
66
66
|
|
|
67
67
|
const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
|
|
68
68
|
const section = between(book, '<!-- eyeprolog-predicate-reference:start -->', '<!-- eyeprolog-predicate-reference:end -->');
|
|
69
69
|
assertEqual(section.split('\n').some((line) => line.trimStart().startsWith('|')), false, 'predicate reference avoids wide table markup');
|
|
70
|
-
assertEqual((section.match(/^- \*\*`/gm) ?? []).length,
|
|
71
|
-
assertEqual((section.match(/<a id="predicate-reference-\d{4}"><\/a>/g) ?? []).length,
|
|
72
|
-
assertEqual((section.match(/\]\(#predicate-reference-\d{4}\)/g) ?? []).length,
|
|
70
|
+
assertEqual((section.match(/^- \*\*`/gm) ?? []).length, 533, 'one reference entry per predicate');
|
|
71
|
+
assertEqual((section.match(/<a id="predicate-reference-\d{4}"><\/a>/g) ?? []).length, 533, 'one explicit anchor per predicate');
|
|
72
|
+
assertEqual((section.match(/\]\(#predicate-reference-\d{4}\)/g) ?? []).length, 533, 'one direct index link per predicate');
|
|
73
73
|
assertNotIncludes(section, '[Symbols](#predicate-reference-symbols)', 'predicate index does not rely on renderer-generated group anchors');
|
|
74
74
|
|
|
75
75
|
const chapter = between(book, '## 39. Predicate reference', '## 40. Running EyeProlog: command line and corpus');
|
|
@@ -4528,6 +4528,82 @@ answer(Result) :- countdown(2048, Result), Result = 2048.
|
|
|
4528
4528
|
if (elapsed >= 20000) throw new Error(`20k must_be/2 calls took ${elapsed}ms`);
|
|
4529
4529
|
},
|
|
4530
4530
|
},
|
|
4531
|
+
{
|
|
4532
|
+
// The pair check runs on every call_with_error_context/2 call, so it is
|
|
4533
|
+
// written as indexed clauses. An if-then-else costs several times what
|
|
4534
|
+
// clause selection does, and this guard used to dominate the wrapper.
|
|
4535
|
+
name: 'call_with_error_context/2 pair check stays off the hot path',
|
|
4536
|
+
run: () => {
|
|
4537
|
+
const input = '%% goal: answer(X)\np(X) :- integer(X).\n' +
|
|
4538
|
+
'loop(0) :- !.\nloop(N) :- call_with_error_context(p(N), c-1), M is N - 1, loop(M).\n' +
|
|
4539
|
+
'answer(ok) :- loop(20000).\n';
|
|
4540
|
+
const started = Date.now();
|
|
4541
|
+
const result = runCli(['-'], { input });
|
|
4542
|
+
const elapsed = Date.now() - started;
|
|
4543
|
+
assertEqual(result.status, 0, `exit status; stderr=${result.stderr}`);
|
|
4544
|
+
assertIncludes(result.stdout, 'answer(ok)', 'loop completes');
|
|
4545
|
+
if (elapsed >= 20000) throw new Error(`20k wrapped calls took ${elapsed}ms`);
|
|
4546
|
+
},
|
|
4547
|
+
},
|
|
4548
|
+
{
|
|
4549
|
+
name: 'sufficient-instantiation list checks reject unknown tails without binding elements',
|
|
4550
|
+
run: () => {
|
|
4551
|
+
const input = ':- use_module(library(si)).\n%% goal: answer(X)\n' +
|
|
4552
|
+
'answer(ok) :- ' +
|
|
4553
|
+
'catch(list_si(X), error(instantiation_error,_), C1 = caught), C1 == caught, var(X), ' +
|
|
4554
|
+
'catch(list_si([a|T]), error(instantiation_error,_), C2 = caught), C2 == caught, var(T), ' +
|
|
4555
|
+
'catch(chars_si(Cs), error(instantiation_error,_), C3 = caught), C3 == caught, var(Cs), ' +
|
|
4556
|
+
'catch(chars_si([a|Tail]), error(instantiation_error,_), C4 = caught), C4 == caught, var(Tail), ' +
|
|
4557
|
+
'list_si([]), list_si([Element]), var(Element), chars_si([a,b]), ' +
|
|
4558
|
+
'\\+ list_si([a|bad]), \\+ chars_si([ab]).\n';
|
|
4559
|
+
const result = runCli(['-'], { input });
|
|
4560
|
+
assertEqual(result.status, 0, `exit status; stderr=${result.stderr}`);
|
|
4561
|
+
assertIncludes(result.stdout, 'answer(ok)', 'list checks preserve sufficient instantiation');
|
|
4562
|
+
},
|
|
4563
|
+
},
|
|
4564
|
+
{
|
|
4565
|
+
// Issue #100: compare_si/3 decides the standard order only when no
|
|
4566
|
+
// instantiation could change it, and raises instantiation_error as
|
|
4567
|
+
// rarely as possible.
|
|
4568
|
+
name: 'compare_si/3 decides the order only when instantiation cannot change it',
|
|
4569
|
+
run: () => {
|
|
4570
|
+
const decided = [
|
|
4571
|
+
['compare_si(O, 1, a)', '<'],
|
|
4572
|
+
['compare_si(O, X, X)', '='],
|
|
4573
|
+
['compare_si(O, f(X), g(Y))', '<'],
|
|
4574
|
+
['compare_si(O, f(X,a), f(X,b))', '<'],
|
|
4575
|
+
['compare_si(O, f(a,b), f(a,b,c))', '<'],
|
|
4576
|
+
['compare_si(O, [a|X], [b|Y])', '<'],
|
|
4577
|
+
['compare_si(O, 1, 1.0)', '>'],
|
|
4578
|
+
];
|
|
4579
|
+
for (const [goal, order] of decided) {
|
|
4580
|
+
const input = ':- use_module(library(si)).\n%% goal: answer(X)\n' +
|
|
4581
|
+
`answer(O) :- ${goal}.\n`;
|
|
4582
|
+
const result = runCli(['-'], { input });
|
|
4583
|
+
assertEqual(result.status, 0, `${goal} status; stderr=${result.stderr}`);
|
|
4584
|
+
assertIncludes(result.stdout, `answer(${order})`, `${goal} order`);
|
|
4585
|
+
}
|
|
4586
|
+
for (const goal of ['compare_si(O, X, 1)', 'compare_si(O, f(a), f(Y))',
|
|
4587
|
+
'compare_si(O, X, Y)', 'compare_si(O, [a|X], [a|Y])']) {
|
|
4588
|
+
const input = ':- use_module(library(si)).\n%% goal: answer(X)\n' +
|
|
4589
|
+
`answer(E) :- catch(${goal}, error(E,_), true).\n`;
|
|
4590
|
+
const result = runCli(['-'], { input });
|
|
4591
|
+
assertEqual(result.status, 0, `${goal} status; stderr=${result.stderr}`);
|
|
4592
|
+
assertIncludes(result.stdout, 'answer(instantiation_error)', `${goal} is undecided`);
|
|
4593
|
+
}
|
|
4594
|
+
},
|
|
4595
|
+
},
|
|
4596
|
+
{
|
|
4597
|
+
// compare_si/3 must not bind anything while deciding.
|
|
4598
|
+
name: 'compare_si/3 leaves its arguments unbound',
|
|
4599
|
+
run: () => {
|
|
4600
|
+
const input = ':- use_module(library(si)).\n%% goal: answer(X)\n' +
|
|
4601
|
+
'answer(ok) :- X = f(Y), compare_si(<, X, g(1)), var(Y).\n';
|
|
4602
|
+
const result = runCli(['-'], { input });
|
|
4603
|
+
assertEqual(result.status, 0, `exit status; stderr=${result.stderr}`);
|
|
4604
|
+
assertIncludes(result.stdout, 'answer(ok)', 'no bindings made');
|
|
4605
|
+
},
|
|
4606
|
+
},
|
|
4531
4607
|
{
|
|
4532
4608
|
// Issue #99: the context element must be a pair, as in Scryer and
|
|
4533
4609
|
// Trealla, and predicate contexts use the predicate-F/A convention.
|