eyeprolog 1.3.78 → 1.3.79
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 +20 -346
- package/package.json +1 -1
- package/src/standard-library.js +31 -12
- package/test/run-regression.mjs +61 -11
- package/the-art-of-eyeprolog.md +39 -26
package/README.md
CHANGED
|
@@ -12,28 +12,22 @@ EyeProlog turns portable ISO Prolog programs into answers and inspectable proofs
|
|
|
12
12
|
<strong>Click the cover to read <em>The Art of EyeProlog</em>.</strong>
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
The book is the reference for the language, command line, JavaScript API,
|
|
20
|
-
examples, proofs, conformance, and implementation.
|
|
15
|
+
The single implementation reference is [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
|
|
16
|
+
It documents the language, built-ins, libraries, command line, JavaScript API,
|
|
17
|
+
examples, proofs, conformance profile, and implementation.
|
|
21
18
|
|
|
22
19
|
## Quick start
|
|
23
20
|
|
|
24
|
-
EyeProlog requires Node.js 18 or newer
|
|
25
|
-
installing:
|
|
21
|
+
EyeProlog requires Node.js 18 or newer:
|
|
26
22
|
|
|
27
23
|
```sh
|
|
28
24
|
node --version
|
|
29
25
|
```
|
|
30
26
|
|
|
31
|
-
If
|
|
32
|
-
[official Node.js download](https://nodejs.org/en/download)
|
|
33
|
-
Distribution packages can provide an older Node.js even on a current operating
|
|
34
|
-
system.
|
|
27
|
+
If necessary, upgrade through a Node version manager or the
|
|
28
|
+
[official Node.js download](https://nodejs.org/en/download).
|
|
35
29
|
|
|
36
|
-
Run EyeProlog without
|
|
30
|
+
Run EyeProlog without installing it globally:
|
|
37
31
|
|
|
38
32
|
```sh
|
|
39
33
|
npx --yes eyeprolog
|
|
@@ -45,8 +39,7 @@ npx --yes eyeprolog
|
|
|
45
39
|
?- halt.
|
|
46
40
|
```
|
|
47
41
|
|
|
48
|
-
For a persistent
|
|
49
|
-
under a user-owned prefix and put that prefix's `bin` directory on `PATH`:
|
|
42
|
+
For a persistent command, use a user-owned npm prefix:
|
|
50
43
|
|
|
51
44
|
```sh
|
|
52
45
|
npm install --global --prefix "$HOME/.local" eyeprolog
|
|
@@ -54,335 +47,26 @@ export PATH="$HOME/.local/bin:$PATH"
|
|
|
54
47
|
eyeprolog
|
|
55
48
|
```
|
|
56
49
|
|
|
57
|
-
Add the `PATH` export to your shell startup file
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
also recommends a Node version manager or a user-owned npm prefix.
|
|
50
|
+
Add the `PATH` export to your shell startup file. Do not use `sudo npm install`;
|
|
51
|
+
npm's [EACCES guidance](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally/)
|
|
52
|
+
also recommends a Node version manager or a user-owned prefix.
|
|
61
53
|
|
|
62
|
-
|
|
54
|
+
Run a program non-interactively:
|
|
63
55
|
|
|
64
56
|
```sh
|
|
65
57
|
printf 'human(socrates).\nmortal(X) :- human(X).\n' |
|
|
66
58
|
npx --yes eyeprolog --proof --goal 'mortal(socrates)' -
|
|
67
59
|
```
|
|
68
60
|
|
|
69
|
-
|
|
70
|
-
Double-quoted text follows the ISO `double_quotes` flag and defaults to a
|
|
71
|
-
proper list of one-character atoms (`chars`), matching Trealla and Scryer.
|
|
72
|
-
|
|
73
|
-
Portable unit tests can be embedded as quads—a query followed by its expected
|
|
74
|
-
top-level answer—and run with `eyeprolog --quads program.pl`:
|
|
75
|
-
|
|
76
|
-
```prolog
|
|
77
|
-
member_test ?- member(X, [prolog, logic]).
|
|
78
|
-
X = prolog
|
|
79
|
-
; X = logic.
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
A label is simply the first argument of the ordinary `(?-)/2` term, so it may
|
|
83
|
-
use any normal Prolog term syntax; EyeProlog only requires it to be ground when
|
|
84
|
-
the quad is checked. A non-ground label is a quad failure, not a source syntax
|
|
85
|
-
error, and later quads still run. When a query has multiple indented answer
|
|
86
|
-
descriptions, each description is checked and counted independently, so one
|
|
87
|
-
failed expectation does not prevent the later ones from running. Following the
|
|
88
|
-
Trealla quad convention, `sto` declares that the query is subject to occurs-check.
|
|
89
|
-
EyeProlog now uses an occurs-check event observed during the query's ordinary
|
|
90
|
-
execution as positive STO evidence, and rejects `sto` when a finite execution
|
|
91
|
-
completes without such an event (for example `?- true. sto.`). If execution is
|
|
92
|
-
cut short by a search/resource boundary, the STO claim remains conservatively
|
|
93
|
-
unverified rather than being guessed.
|
|
94
|
-
For nontermination expectations, `loops` is kept distinct from resource
|
|
95
|
-
exhaustion: structural loop evidence may satisfy `loops`, while a bounded
|
|
96
|
-
search that cannot establish the requested answer sequence is reported as
|
|
97
|
-
`UNDECIDED`. In CLI quad mode, failures use exit status `1`; if there are no
|
|
98
|
-
failures but at least one undecided quad, the exit status is `2`.
|
|
99
|
-
|
|
100
|
-
## Tabling and well-founded negation
|
|
101
|
-
|
|
102
|
-
In normal mode, EyeProlog automatically tables eligible positive recursive
|
|
103
|
-
predicates. For large finite, function-free Datalog dependency cones it may use
|
|
104
|
-
one shared relation-wide table, so an open query such as `tc(X, Y)` computes a
|
|
105
|
-
finite closure once and bound recursive calls can reuse indexed answers. The
|
|
106
|
-
choice of when to use relation-wide tabling is an implementation optimization,
|
|
107
|
-
not a language-level threshold or directive.
|
|
108
|
-
|
|
109
|
-
Recursive nonterminals reached through `phrase/2-3` use a dedicated table
|
|
110
|
-
scope keyed by the complete invocation rather than the caller's general memo.
|
|
111
|
-
When a new input is seen, recursive DCGs that static analysis proves consume a
|
|
112
|
-
list tail on every recursive step run directly without automatic tabling; this
|
|
113
|
-
avoids building and retaining a family of suffix tables that cannot help the
|
|
114
|
-
next distinct input. If the same `phrase/2-3` invocation repeats, normal tabling
|
|
115
|
-
is enabled again and its small completed table can be reused. The retained
|
|
116
|
-
phrase table is also bounded, with active fixed points never evicted. This
|
|
117
|
-
keeps both long-running filters such as `\+ phrase((..., Pattern), Sequence)`
|
|
118
|
-
and repeated same-input probes bounded without turning memory safety into a
|
|
119
|
-
per-call cache-eviction cost.
|
|
120
|
-
|
|
121
|
-
Finite-tree unification also accepts an internal proven-nonoccurrence hint: when
|
|
122
|
-
the solver can prove that a variable cannot occur in the value it is about to
|
|
123
|
-
receive, that binding skips an otherwise redundant occurs traversal. The main
|
|
124
|
-
source-level case is conservative first use in a freshly renamed clause, inspired
|
|
125
|
-
by the local-variable optimization used by WAM-family systems; native construction
|
|
126
|
-
paths such as relational `length/2` reuse the same unifier mechanism. Repeated
|
|
127
|
-
variables, variables seen earlier in the clause, and ordinary public unification
|
|
128
|
-
remain fully occurs-checked. This is a proof local to one binding, not a WAM-style
|
|
129
|
-
local/global variable stack. `phrase/2` likewise supplies its fixed `[]`
|
|
130
|
-
remainder directly to the grammar; `phrase/3` retains its delayed final output
|
|
131
|
-
unification for steadfastness.
|
|
132
|
-
|
|
133
|
-
### Delayed disequality with `dif/2`
|
|
134
|
-
|
|
135
|
-
The normal EyeProlog runtime provides `dif/2` as a conforming extension;
|
|
136
|
-
`--iso-strict` remains limited to ISO/IEC 13211-1 and does not expose it.
|
|
137
|
-
Unlike `\=/2`, which only tests whether two terms are non-unifiable *now*,
|
|
138
|
-
`dif/2` can succeed with a residual disequality constraint and reject a later
|
|
139
|
-
binding that would make the terms identical. For example,
|
|
140
|
-
`dif(X, Y), X = Y` fails, while `dif(X-Y, 1-2), X = Y, Y = 1` succeeds once
|
|
141
|
-
the structural constraint becomes provably satisfied.
|
|
142
|
-
|
|
143
|
-
The implementation uses backtracking-safe annotated variables in `Env`. A
|
|
144
|
-
pending constraint is indexed by every currently unbound variable it mentions;
|
|
145
|
-
variable aliasing and later bindings reindex the annotation, entailed constraints
|
|
146
|
-
are removed, and violated constraints make unification fail. The interactive
|
|
147
|
-
top level includes pending `dif/2` goals in residual answers. See
|
|
148
|
-
[`examples/dif-constraints.pl`](examples/dif-constraints.pl).
|
|
149
|
-
|
|
150
|
-
### Attributed variables and CLP(Z)
|
|
151
|
-
|
|
152
|
-
`library(atts)` exposes Scryer-style attributed-variable operations on the same
|
|
153
|
-
persistent `Env` machinery used by `dif/2`: `put_atts/2`, `get_atts/2`,
|
|
154
|
-
`put_attr/3`, `get_attr/3`, `del_attr/2`, `term_attributed_variables/2`, and
|
|
155
|
-
`call_residue_vars/2`. The latter reports variables whose residual attributes or
|
|
156
|
-
constraints were created or modified by a goal, including native `dif/2` residues.
|
|
157
|
-
`:- attribute ...` declarations are accepted, `verify_attributes/3` runs before
|
|
158
|
-
an attributed binding is committed, and the hook's returned goals run after
|
|
159
|
-
that binding. Attribute state follows variable representatives and ordinary
|
|
160
|
-
Prolog backtracking, and the REPL projects module `attribute_goals//1` hooks as
|
|
161
|
-
residual goals. See [`examples/attributed-variables.pl`](examples/attributed-variables.pl).
|
|
162
|
-
|
|
163
|
-
`library(clpz)` is the MIT-licensed Scryer Prolog implementation of CLP(Z),
|
|
164
|
-
bundled as `src/lib/clpz.pl`. It provides relational integer arithmetic,
|
|
165
|
-
finite-domain constraints, reification, labeling, global constraints such as
|
|
166
|
-
`all_distinct/1`, `global_cardinality/2,3`, `cumulative/1,2`, `circuit/1`,
|
|
167
|
-
`disjoint2/1`, and `automaton/3,8`, plus domain reflection predicates. The
|
|
168
|
-
bundled source is synchronized with Scryer commit
|
|
169
|
-
`e3df91e25f8a09ee942c04e8baef553bba5c6110` (Git blob
|
|
170
|
-
`806445c11e14c8b2515f3de7f309e0ac04d9ad04`).
|
|
171
|
-
|
|
172
|
-
EyeProlog's runtime supplies the generic facilities used by that Prolog source:
|
|
173
|
-
attributed variables, user `term_expansion/2` and `goal_expansion/2`, DCG
|
|
174
|
-
expansion through `expand_term/2`, module-aware meta-calls, a backtrackable
|
|
175
|
-
blackboard, and the support modules `assoc`, `pairs`, `between`, `dcgs`, `terms`,
|
|
176
|
-
`error`, `si`, `freeze`, `arithmetic`, `debug`, and `format`.
|
|
177
|
-
|
|
178
|
-
Recursion through negation is explicit. EyeProlog provides `tnot/1` for
|
|
179
|
-
well-founded negation over finite, range-restricted, function-free Datalog
|
|
180
|
-
components. Ordinary `\+/1` remains negation-as-failure and is not silently
|
|
181
|
-
reinterpreted as WFS.
|
|
182
|
-
|
|
183
|
-
```prolog
|
|
184
|
-
move(1, 2).
|
|
185
|
-
move(2, 1).
|
|
186
|
-
win(X) :- move(X, Y), tnot(win(Y)).
|
|
187
|
-
|
|
188
|
-
%% goal: win(X)
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
A cycle through `tnot/1` can leave atoms *undefined* rather than true or false.
|
|
192
|
-
EyeProlog exposes those as conditional successes so they can participate in
|
|
193
|
-
collectors such as `findall/3`; it does not currently expose a residual-program
|
|
194
|
-
API. Direct `tnot/1` calls must be ground. Variables used in an eligible WFS
|
|
195
|
-
rule are range-restricted by positive body literals before they are negated.
|
|
196
|
-
|
|
197
|
-
The normal-mode statistics interface includes `wfs_fixpoint_rounds` and
|
|
198
|
-
`wfs_undefined_answers`:
|
|
199
|
-
|
|
200
|
-
```prolog
|
|
201
|
-
statistics(wfs_fixpoint_rounds, Rounds).
|
|
202
|
-
statistics(wfs_undefined_answers, UndefinedObservations).
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
Both automatic tabling and `tnot/1` are EyeProlog extensions. Strict ISO mode
|
|
206
|
-
disables automatic tabling and does not provide `tnot/1`.
|
|
207
|
-
|
|
208
|
-
## Cleanup-aware control
|
|
209
|
-
|
|
210
|
-
Normal mode provides `call_cleanup/2` and `setup_call_cleanup/3` for resource
|
|
211
|
-
lifetimes that follow Prolog search. Cleanup runs exactly once when the protected
|
|
212
|
-
goal completes deterministically, is exhausted, is cut or otherwise pruned, the
|
|
213
|
-
top level stops answer enumeration, or an exception unwinds the search.
|
|
214
|
-
`setup_call_cleanup/3` runs Setup once and installs Cleanup only after Setup
|
|
215
|
-
succeeds. On ordinary pruning Cleanup sees the current goal bindings; during
|
|
216
|
-
exception unwinding bindings made by the protected goal have already been
|
|
217
|
-
unwound. Cleanup failure is ignored, and an exception already being propagated
|
|
218
|
-
takes precedence over a cleanup exception. Nested cleanups run inside-out.
|
|
219
|
-
|
|
220
|
-
These predicates are EyeProlog normal-mode extensions and are absent from
|
|
221
|
-
`--iso-strict`. Their implementation is lifecycle-aware: the interactive top
|
|
222
|
-
level can report a remaining choicepoint without speculatively requesting the
|
|
223
|
-
next solution, while abandoning that choicepoint still closes protected
|
|
224
|
-
resources.
|
|
225
|
-
|
|
226
|
-
## OpenRuleBench portable profile
|
|
227
|
-
|
|
228
|
-
The `openrulebench/` directory contains a deterministic four-engine adaptation
|
|
229
|
-
for EyeProlog, Trealla, Scryer, and SWI-Prolog. Its default `portable` profile
|
|
230
|
-
keeps the characteristic joins, recursive closures, and WFS cases while
|
|
231
|
-
avoiding benchmark sizes that require multi-gigabyte collectors on some
|
|
232
|
-
engines. Run EyeProlog's complete profile with:
|
|
233
|
-
|
|
234
|
-
```sh
|
|
235
|
-
./openrulebench/run-eyeprolog.mjs
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
The benchmark README records the expected answer counts. Timing values are
|
|
239
|
-
machine-dependent; use the same generated profile when comparing engines.
|
|
240
|
-
|
|
241
|
-
## Strict ISO/IEC 13211-1 core
|
|
242
|
-
|
|
243
|
-
For portability and conformance work, run the Part 1 core with Technical
|
|
244
|
-
Corrigenda 1–3 in strict mode:
|
|
245
|
-
|
|
246
|
-
```sh
|
|
247
|
-
eyeprolog --iso-strict
|
|
248
|
-
eyeprolog --iso-strict --goal 'p(X)' program.pl
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
The equivalent JavaScript option is `isoStrict: true`. Strict mode keeps
|
|
252
|
-
EyeProlog's documented implementation-defined Unicode scalar processor
|
|
253
|
-
character set, while excluding normal-profile language extensions such as Part
|
|
254
|
-
2 module compatibility forms, Part 3 DCG expansion, quads, extra libraries,
|
|
255
|
-
automatic tabling, and non-standard flags/control facilities. Normal mode is
|
|
256
|
-
unchanged.
|
|
257
|
-
|
|
258
|
-
This README intentionally stays at the project-overview level. The detailed
|
|
259
|
-
implementation reference is [*The Art of EyeProlog*](the-art-of-eyeprolog.md).
|
|
260
|
-
The current Part 1 audit status and closure criteria are recorded in
|
|
261
|
-
[`test/conformance/ISO-COMPLIANCE.md`](test/conformance/ISO-COMPLIANCE.md);
|
|
262
|
-
implementation-defined decisions are indexed in
|
|
263
|
-
[`ISO-IMPLEMENTATION-DEFINED.md`](test/conformance/ISO-IMPLEMENTATION-DEFINED.md). The complete
|
|
264
|
-
vendored WG17 syntax corpus and the strict ISO regression suite run as release
|
|
265
|
-
gates.
|
|
266
|
-
|
|
267
|
-
The release-facing Part 1 audit ledger has explicit dispositions for its tracked requirements. This implementation evidence is not an independent ISO certification.
|
|
268
|
-
|
|
269
|
-
## Module and definite clause grammar compatibility profiles
|
|
270
|
-
|
|
271
|
-
Normal EyeProlog supports the widely used `module/2`, `use_module/1-2`,
|
|
272
|
-
`meta_predicate/1`, and `Module:Goal` interface reflected in later WG17 module
|
|
273
|
-
amendment work. This is a practical module compatibility profile; EyeProlog
|
|
274
|
-
does **not** currently claim a clause-by-clause implementation or certification
|
|
275
|
-
of the complete ISO/IEC 13211-2:2000 module model.
|
|
276
|
-
|
|
277
|
-
Definite clause grammar support follows the ISO/IEC TS 13211-3 grammar-rule and
|
|
278
|
-
`phrase/2-3` model and is exercised by the conformance corpus. As with Part 1,
|
|
279
|
-
that implementation evidence is not an independent certification of every
|
|
280
|
-
Part 3 requirement. For example:
|
|
281
|
-
|
|
282
|
-
```prolog
|
|
283
|
-
sentence --> [hello], noun.
|
|
284
|
-
noun --> [world] | [prolog].
|
|
285
|
-
|
|
286
|
-
%% goal: phrase(sentence, Words)
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
For a larger bidirectional example, see
|
|
290
|
-
[`examples/dcg-expression-language.pl`](examples/dcg-expression-language.pl).
|
|
291
|
-
It parses precedence-sensitive arithmetic into an AST, evaluates expressions
|
|
292
|
-
with variables, generates tokens back from an AST with only the necessary
|
|
293
|
-
parentheses, round-trips the generated form, and demonstrates `phrase/3`
|
|
294
|
-
remainder handling. The example uses accumulator nonterminals for
|
|
295
|
-
left-associative operators, so state is handed repeatedly from one nonterminal
|
|
296
|
-
to the next rather than hidden in host code.
|
|
297
|
-
|
|
298
|
-
Deep finite DCG traversal is kept relational but does not have to consume one
|
|
299
|
-
general solver frame per token. In particular, the interoperable `... //0`
|
|
300
|
-
helper from `library(iso_ext)` can scan a finite compact list iteratively, and a
|
|
301
|
-
following grammar that is statically known to leave the DCG state unchanged can
|
|
302
|
-
be continued without rebuilding a full clause-resolution frame for every
|
|
303
|
-
suffix. Open and remainder-producing uses still retain the ordinary DCG
|
|
304
|
-
solutions and backtracking behavior.
|
|
61
|
+
## Links
|
|
305
62
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
`library(atts)`, or `library(clpz)`.
|
|
314
|
-
Portable text
|
|
315
|
-
predicates use ISO atoms or character lists. The old catch-all
|
|
316
|
-
`library(eyeprolog)` module is no longer needed.
|
|
317
|
-
|
|
318
|
-
## Trealla and Scryer interoperability
|
|
319
|
-
|
|
320
|
-
EyeProlog keeps a conservative source-level interoperability profile separate
|
|
321
|
-
from the larger EyeProlog library surface. `library(lists)` follows the common
|
|
322
|
-
Trealla/Scryer organization for predicates such as `member/2`, `memberchk/2`,
|
|
323
|
-
`append/2-3`, `nth0/3-4`, `nth1/3-4`, `length/2`, `maplist/2-8`, and
|
|
324
|
-
`foldl/4-6`. Its `length/2` remains relational: with both arguments variable,
|
|
325
|
-
`length(Xs, N)` enumerates lists of increasing length together with `N = 0, 1,
|
|
326
|
-
2, ...`. Open-ended generation uses the normal memory guard with recovery
|
|
327
|
-
headroom, so an exhausted finite heap is reported as a catchable
|
|
328
|
-
`resource_error(memory)` instead of degenerating into quadratic list checks.
|
|
329
|
-
|
|
330
|
-
`library(iso_ext)` is also accepted as a common interop module name.
|
|
331
|
-
EyeProlog exports `call_nth/2`, `time/1`, and the DCG helper `... //0` there.
|
|
332
|
-
The latter describes an arbitrary number of input elements and supports the
|
|
333
|
-
nonterminal hand-off benchmark used by the interoperability tests. These common predicates
|
|
334
|
-
may be imported explicitly, while source/CLI/API dependency loading can resolve
|
|
335
|
-
their unqualified forms conservatively. For Trealla-style interactive timing,
|
|
336
|
-
`time/1` is also available directly in the normal EyeProlog runtime; strict ISO
|
|
337
|
-
mode does not expose it.
|
|
338
|
-
`library(lists)`, `library(iso_ext)`, and `library(freeze)` follow the focused
|
|
339
|
-
module organization used by Trealla and Scryer. EyeProlog's legacy
|
|
340
|
-
`library(prologue)` is now a compatibility facade over these canonical modules
|
|
341
|
-
and `library(between)`, so it can be imported before or after the focused
|
|
342
|
-
libraries without duplicate-import errors.
|
|
343
|
-
|
|
344
|
-
`library(lambda)` follows Scryer's higher-order lambda notation, adapted from
|
|
345
|
-
Ulrich Neumerkel's permissively licensed implementation. Importing it installs
|
|
346
|
-
the `+\` operator and enables closures such as `\X^Goal` and
|
|
347
|
-
`Free+\X^Goal`. Parameters are supplied by `call/N`; variables not listed in
|
|
348
|
-
`Free` are copied afresh for each invocation, while explicitly free variables
|
|
349
|
-
remain shared. For example:
|
|
350
|
-
|
|
351
|
-
```prolog
|
|
352
|
-
:- use_module(library(lambda)).
|
|
353
|
-
:- use_module(library(lists)).
|
|
354
|
-
|
|
355
|
-
all_positive(Xs) :- maplist(\X^(X > 0), Xs).
|
|
356
|
-
all_equal(Y, Xs) :- maplist(Y+\X^(X = Y), Xs).
|
|
357
|
-
```
|
|
358
|
-
|
|
359
|
-
The explicit import is intentional: unlike ordinary predicate autoloading, the
|
|
360
|
-
lambda syntax also changes the active operator table.
|
|
361
|
-
|
|
362
|
-
Outside `--iso-strict`, an otherwise undefined unqualified call may autoload a
|
|
363
|
-
predicate only when the interop profile has one canonical EyeProlog provider.
|
|
364
|
-
For example, `member/2` autoloads from `library(lists)`, `call_nth/2` from
|
|
365
|
-
`library(iso_ext)`, `call_residue_vars/2` from `library(atts)`, and `between/3`
|
|
366
|
-
from `library(between)`. Use `--no-autoload` to disable this
|
|
367
|
-
convenience. Strict ISO mode never autoloads library predicates.
|
|
368
|
-
|
|
369
|
-
Use `-w` / `--warnings` to diagnose dependencies outside the interop profile,
|
|
370
|
-
or `--portable` to make such diagnostics fail the run. This catches both
|
|
371
|
-
implementation-specific library names and EyeProlog-only predicates such as
|
|
372
|
-
`set_nth0/4` even when they live in an otherwise common module.
|
|
373
|
-
|
|
374
|
-
Cross-engine smoke tests live in `test/run-interop.mjs`. With Trealla (`tpl`)
|
|
375
|
-
and Scryer (`scryer-prolog`) installed, run:
|
|
376
|
-
|
|
377
|
-
```sh
|
|
378
|
-
npm run test:interop
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
This optional check runs the same portable Towers of Hanoi source under
|
|
382
|
-
EyeProlog, Trealla, and Scryer. The default `npm test` does not require external
|
|
383
|
-
Prolog implementations; it does validate all four generated OpenRuleBench
|
|
384
|
-
source trees and their engine-specific tabling and WFS adaptations. Run those
|
|
385
|
-
fast structural checks separately with `npm run test:openrulebench`.
|
|
63
|
+
- [The Art of EyeProlog](https://eyereasoner.github.io/eyeprolog/the-art-of-eyeprolog) — complete reference
|
|
64
|
+
- [Why EyeProlog?](https://eyereasoner.github.io/eyeprolog/why-eyeprolog) — project scope and design
|
|
65
|
+
- [Playground](https://eyereasoner.github.io/eyeprolog/playground) — run EyeProlog in a browser
|
|
66
|
+
- [Examples](examples) — runnable programs and checked output
|
|
67
|
+
- [ISO conformance audit](test/conformance/ISO-COMPLIANCE.md) — supported Part 1 profile
|
|
68
|
+
- [Conformance report](conformance-report.md) — generated public corpus summary
|
|
69
|
+
- [OpenRuleBench](openrulebench/README.md) — portable benchmark profile
|
|
386
70
|
|
|
387
71
|
## Development
|
|
388
72
|
|
|
@@ -393,14 +77,4 @@ npm install
|
|
|
393
77
|
npm test
|
|
394
78
|
```
|
|
395
79
|
|
|
396
|
-
The GitHub test workflow runs the complete suite and an npm package dry-run on
|
|
397
|
-
both the minimum supported Node.js 18 release line and Node.js 24. Publishing
|
|
398
|
-
repeats those release checks before uploading the package.
|
|
399
|
-
|
|
400
|
-
The runtime JavaScript modules stay flat under `src/`; the existing `src/lib/`
|
|
401
|
-
directory contains the portable Prolog library modules. See
|
|
402
|
-
[`src/ARCHITECTURE.md`](src/ARCHITECTURE.md) for the source-layer boundaries,
|
|
403
|
-
facade modules, dependency rule, and the requirement that architectural cleanup
|
|
404
|
-
must preserve the existing solver hot paths and benchmark performance.
|
|
405
|
-
|
|
406
80
|
EyeProlog is released under the [MIT License](LICENSE.md).
|
package/package.json
CHANGED
package/src/standard-library.js
CHANGED
|
@@ -69,25 +69,44 @@ export const eyePrologNativeLibraryIndicators = Object.freeze([
|
|
|
69
69
|
'in/2', 'ins/2', 'all_different/1', 'all_distinct/1', 'nvalue/2', 'sum/3',
|
|
70
70
|
'scalar_product/4', 'tuples_in/2', 'labeling/2', 'label/1',
|
|
71
71
|
'indomain/1', 'lex_chain/1', 'serialized/2', 'global_cardinality/2',
|
|
72
|
-
'global_cardinality/3', 'circuit/1', '
|
|
72
|
+
'global_cardinality/3', 'circuit/1', 'cumulative/1', 'cumulative/2',
|
|
73
|
+
'disjoint2/1', 'automaton/3', 'automaton/8', 'chain/2', 'element/3', 'zcompare/3',
|
|
73
74
|
'fd_var/1', 'fd_inf/2', 'fd_sup/2', 'fd_size/2', 'fd_dom/2',
|
|
75
|
+
'clpz_t/2', '#=/3', '#</3',
|
|
74
76
|
]);
|
|
75
77
|
export const eyePrologPortableLibraryIndicators = Object.freeze([
|
|
76
78
|
'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
|
|
77
|
-
'
|
|
78
|
-
'
|
|
79
|
-
'
|
|
80
|
-
'
|
|
81
|
-
'
|
|
82
|
-
'
|
|
83
|
-
'
|
|
84
|
-
'
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
'
|
|
79
|
+
'lsb/2', 'msb/2', 'popcount/2',
|
|
80
|
+
'empty_assoc/1', 'assoc_to_list/2', 'get_assoc/3', 'put_assoc/4',
|
|
81
|
+
'between/3', 'gen_int/1', 'gen_nat/1', 'numlist/2', 'numlist/3', 'repeat/1',
|
|
82
|
+
'lt/2', 'gt/2', 'le/2', 'ge/2',
|
|
83
|
+
'difference/3',
|
|
84
|
+
'seq/3', 'seqq/3',
|
|
85
|
+
'debug/1', 'debug/3', 'nodebug/1', 'bb_get/2', 'bb_b_put/2',
|
|
86
|
+
'must_be/2', 'can_be/2', 'instantiation_error/0', 'instantiation_error/1',
|
|
87
|
+
'domain_error/2', 'domain_error/3', 'type_error/2', 'type_error/3',
|
|
88
|
+
'representation_error/1', 'resource_error/1', 'call_with_error_context/2',
|
|
89
|
+
'format/2',
|
|
90
|
+
'forall/2', 'succ/2', 'cfor/3', 'findall/4', 'variant/2', '.../2',
|
|
88
91
|
'^/3', '^/4', '^/5', '^/6', '^/7', '^/8', '^/9', '^/10',
|
|
89
92
|
'\\/1', '\\/2', '\\/3', '\\/4', '\\/5', '\\/6', '\\/7', '\\/8',
|
|
90
93
|
'+\\/2', '+\\/3', '+\\/4', '+\\/5', '+\\/6', '+\\/7', '+\\/8', '+\\/9',
|
|
94
|
+
'member/2', 'memberchk/2', 'select/3', 'append/2', 'append/3', 'last/2', 'same_length/2',
|
|
95
|
+
'nth0/3', 'nth0/4', 'nth1/3', 'nth1/4', 'set_nth0/4', 'take/3', 'drop/3', 'slice/4', 'reverse/2',
|
|
96
|
+
'length/2', 'maplist/2', 'maplist/3', 'maplist/4', 'maplist/5',
|
|
97
|
+
'maplist/6', 'maplist/7', 'maplist/8', 'foldl/4', 'foldl/5', 'foldl/6',
|
|
98
|
+
'sum_list/2', 'min_list/2', 'max_list/2', 'list_to_set/2',
|
|
99
|
+
'pairs_keys_values/3', 'pairs_keys/2', 'pairs_values/2',
|
|
100
|
+
'group_pairs_by_key/2', 'map_list_to_pairs/3',
|
|
101
|
+
'smallest_divisor_from/3',
|
|
102
|
+
'random/3',
|
|
103
|
+
'atom_si/1', 'integer_si/1', 'atomic_si/1', 'list_si/1', 'character_si/1',
|
|
104
|
+
'term_si/1', 'chars_si/1', 'dif_si/2', 'not_si/1', 'when_si/2',
|
|
105
|
+
'matches/3', 'split/3', 'replace/4', 'lowercase/2', 'uppercase/2', 'trim/2',
|
|
106
|
+
'number_string/2', 'atom_string/2', 'term_string/2', 'string_concat/3',
|
|
107
|
+
'contains/2', 'matches/2', 'join/3', 'substring/4',
|
|
108
|
+
'numbervars/3', 'copy_term_nat/2',
|
|
109
|
+
'uuid/3',
|
|
91
110
|
]);
|
|
92
111
|
export const eyePrologLibraryIndicators = Object.freeze([
|
|
93
112
|
...eyePrologPortableLibraryIndicators,
|
package/test/run-regression.mjs
CHANGED
|
@@ -3987,7 +3987,15 @@ function documentationSyncCases() {
|
|
|
3987
3987
|
},
|
|
3988
3988
|
{
|
|
3989
3989
|
name: 'book EyeProlog library matches runtime registry',
|
|
3990
|
-
run: () =>
|
|
3990
|
+
run: () => {
|
|
3991
|
+
assertArrayEqual(bookEyePrologLibraryNames(), registeredEyePrologLibraryNames(), 'EyeProlog library predicates');
|
|
3992
|
+
assertArrayEqual(bookLibraryModuleIssues(), [], 'library module export catalog');
|
|
3993
|
+
const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
|
|
3994
|
+
assertIncludes(book, `**${eyePrologLibraryIndicators.length} distinct non-ISO library and normal-extension predicate`, 'library predicate count');
|
|
3995
|
+
assertIncludes(book, `**${eyePrologPortableLibraryIndicators.length} are defined entirely as ordinary Prolog clauses**`, 'portable library count');
|
|
3996
|
+
assertIncludes(book, `**${eyePrologNativeLibraryIndicators.length} use host support**`, 'host-supported library count');
|
|
3997
|
+
assertIncludes(book, `**${createDefaultRegistry().defs.size + eyePrologLibraryIndicators.length} distinct predicate indicators**`, 'combined catalog count');
|
|
3998
|
+
},
|
|
3991
3999
|
},
|
|
3992
4000
|
{
|
|
3993
4001
|
name: 'README cover links to the book and the book documents runtime boundaries',
|
|
@@ -3999,11 +4007,10 @@ function documentationSyncCases() {
|
|
|
3999
4007
|
'<a href="https://eyereasoner.github.io/eyeprolog/the-art-of-eyeprolog">\n <img src="book-assets/title-page.svg" alt="Read The Art of EyeProlog"',
|
|
4000
4008
|
'README cover links to the book',
|
|
4001
4009
|
);
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
'src/
|
|
4005
|
-
|
|
4006
|
-
'src/playground-worker.js']) {
|
|
4010
|
+
const documentedSources = ['src/iso.js', 'src/dcg.js', 'src/atts.js', 'src/standard-library.js',
|
|
4011
|
+
...[...standardLibrarySources.values()].map((entry) => entry.filename),
|
|
4012
|
+
'src/playground-worker.js'];
|
|
4013
|
+
for (const filename of documentedSources) {
|
|
4007
4014
|
assertEqual(fs.existsSync(path.join(packageRoot, filename)), true, `${filename} exists`);
|
|
4008
4015
|
assertIncludes(book, filename, `book documents ${filename}`);
|
|
4009
4016
|
}
|
|
@@ -4161,6 +4168,11 @@ function documentationSyncCases() {
|
|
|
4161
4168
|
]) assertIncludes(book, name, `book ${name}`);
|
|
4162
4169
|
assertIncludes(readme, 'implementation reference is [*The Art of EyeProlog*]', 'README book hand-off');
|
|
4163
4170
|
assertIncludes(readme, 'test/conformance/ISO-COMPLIANCE.md', 'README concise audit link');
|
|
4171
|
+
assertEqual(readme.split('\n').length <= 100, true, 'README remains a compact entry point');
|
|
4172
|
+
for (const heading of ['## Tabling', '## Cleanup-aware control', '## Strict ISO',
|
|
4173
|
+
'## Module and definite clause grammar', '## Trealla and Scryer interoperability']) {
|
|
4174
|
+
assertNotIncludes(readme, heading, `README delegates ${heading} to the book`);
|
|
4175
|
+
}
|
|
4164
4176
|
assertEqual(readme.includes('2026-08-23 draft items #73-#76'), false, 'README omits audit-history detail');
|
|
4165
4177
|
assertIncludes(profile, 'Part 1 processor, syntax, semantic, built-in, and arithmetic', 'Why EyeProlog audit state');
|
|
4166
4178
|
},
|
|
@@ -5119,8 +5131,8 @@ answer(ok) :-
|
|
|
5119
5131
|
assertEqual(Boolean(library.get('call_cleanup', 2)), true, 'call_cleanup/2 is an EyeProlog cleanup control');
|
|
5120
5132
|
assertEqual(registry.get('setup_call_cleanup', 3), null, 'setup_call_cleanup/3 is absent from the ISO registry');
|
|
5121
5133
|
assertEqual(Boolean(library.get('setup_call_cleanup', 3)), true, 'setup_call_cleanup/3 is an EyeProlog cleanup control');
|
|
5122
|
-
assertEqual(registeredNativeEyePrologLibraryNames().length,
|
|
5123
|
-
assertEqual(eyePrologPortableLibraryIndicators.length,
|
|
5134
|
+
assertEqual(registeredNativeEyePrologLibraryNames().length, 57, 'public host-supported EyeProlog library count');
|
|
5135
|
+
assertEqual(eyePrologPortableLibraryIndicators.length, 135, 'portable Prolog library count');
|
|
5124
5136
|
assertEqual(eyePrologInteropLibraryIndicators.length, 30, 'cross-implementation interop profile count');
|
|
5125
5137
|
assertEqual(eyePrologInteropLibraryModules.join(','), 'lists,iso_ext,lambda,atts,freeze', 'common explicit library module profile');
|
|
5126
5138
|
assertEqual(eyePrologInteropAutoload['member/2'], 'lists', 'member/2 canonical autoload');
|
|
@@ -5130,9 +5142,9 @@ answer(ok) :-
|
|
|
5130
5142
|
assertEqual(eyePrologInteropAutoload['time/1'], 'iso_ext', 'time/1 canonical interop autoload');
|
|
5131
5143
|
assertEqual(eyePrologInteropAutoload['.../2'], 'iso_ext', '.../2 canonical interop autoload');
|
|
5132
5144
|
assertEqual(eyePrologInteropAutoload['set_nth0/4'] ?? null, null, 'EyeProlog-only set_nth0/4 is not autoloadable');
|
|
5133
|
-
assertEqual(eyePrologNativeLibraryIndicators.length,
|
|
5145
|
+
assertEqual(eyePrologNativeLibraryIndicators.length, 57, 'host-supported library count');
|
|
5134
5146
|
assertEqual(eyePrologNativeLibraryIndicators.slice(0, 3).join(','), 'call_nth/2,freeze/2,dif/2', 'control and constraint predicates requiring host support');
|
|
5135
|
-
assertEqual(eyePrologLibraryIndicators.length,
|
|
5147
|
+
assertEqual(eyePrologLibraryIndicators.length, 192, 'complete non-ISO EyeProlog library surface');
|
|
5136
5148
|
assertEqual(registry.get('eyeprolog__call_nth', 2), null, 'private call_nth adapter is absent from ISO registry');
|
|
5137
5149
|
assertEqual(Boolean(library.get('eyeprolog__call_nth', 2)), true, 'private call_nth adapter is registered for EyeProlog');
|
|
5138
5150
|
assertEqual(Boolean(library.get('eyeprolog__call_residue_vars', 2)), true, 'private call_residue_vars adapter is registered for EyeProlog');
|
|
@@ -6292,7 +6304,45 @@ function bookBuiltinNames() {
|
|
|
6292
6304
|
|
|
6293
6305
|
function bookEyePrologLibraryNames() {
|
|
6294
6306
|
const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
|
|
6295
|
-
|
|
6307
|
+
const iso = new Set(registeredBuiltinNames());
|
|
6308
|
+
return documentedBuiltinNames(
|
|
6309
|
+
between(book, '<!-- eyeprolog-library-catalog:start -->', '<!-- eyeprolog-library-catalog:end -->'),
|
|
6310
|
+
2,
|
|
6311
|
+
).filter((indicator) => !iso.has(indicator));
|
|
6312
|
+
}
|
|
6313
|
+
|
|
6314
|
+
function bookLibraryModuleIssues() {
|
|
6315
|
+
const book = fs.readFileSync(path.join(packageRoot, 'the-art-of-eyeprolog.md'), 'utf8');
|
|
6316
|
+
const section = between(book, '<!-- eyeprolog-library-catalog:start -->', '<!-- eyeprolog-library-catalog:end -->');
|
|
6317
|
+
const documented = new Map();
|
|
6318
|
+
for (const line of section.split('\n')) {
|
|
6319
|
+
const match = line.match(/^\|\s*`library\(([^)`]+)\)`\s*\|/);
|
|
6320
|
+
if (match == null) continue;
|
|
6321
|
+
documented.set(match[1], documentedBuiltinNames(line, 2));
|
|
6322
|
+
}
|
|
6323
|
+
|
|
6324
|
+
const issues = [];
|
|
6325
|
+
for (const [moduleName, entry] of standardLibrarySources) {
|
|
6326
|
+
const parsed = Program.parse(entry.source);
|
|
6327
|
+
const definition = parsed.modules.get(moduleName);
|
|
6328
|
+
if (definition == null) {
|
|
6329
|
+
issues.push(`missing module declaration for ${moduleName}`);
|
|
6330
|
+
continue;
|
|
6331
|
+
}
|
|
6332
|
+
const actual = [...definition.exports.keys()].sort();
|
|
6333
|
+
const expected = documented.get(moduleName);
|
|
6334
|
+
if (expected == null) {
|
|
6335
|
+
issues.push(`book catalog omits library(${moduleName})`);
|
|
6336
|
+
continue;
|
|
6337
|
+
}
|
|
6338
|
+
if (JSON.stringify(expected) !== JSON.stringify(actual)) {
|
|
6339
|
+
issues.push(`library(${moduleName}) exports: expected ${actual.join(', ')}, documented ${expected.join(', ')}`);
|
|
6340
|
+
}
|
|
6341
|
+
}
|
|
6342
|
+
for (const moduleName of documented.keys()) {
|
|
6343
|
+
if (!standardLibrarySources.has(moduleName)) issues.push(`book catalogs unknown library(${moduleName})`);
|
|
6344
|
+
}
|
|
6345
|
+
return issues.sort();
|
|
6296
6346
|
}
|
|
6297
6347
|
|
|
6298
6348
|
function bookBuiltinSummary() {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6211,16 +6211,18 @@ so side effects occur in Prolog execution order.
|
|
|
6211
6211
|
|
|
6212
6212
|
### The EyeProlog library
|
|
6213
6213
|
|
|
6214
|
-
EyeProlog exposes **
|
|
6215
|
-
indicators in
|
|
6216
|
-
Prolog clauses** in focused modules under
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6214
|
+
EyeProlog exposes **192 distinct non-ISO library and normal-extension predicate
|
|
6215
|
+
indicators** in addition to the 129 indicators in its isolated ISO profile.
|
|
6216
|
+
**135 are defined entirely as ordinary Prolog clauses** in focused modules under
|
|
6217
|
+
`src/lib/`; **57 use host support** for control, attributed variables,
|
|
6218
|
+
constraints, or observability. The ISO and library catalogs therefore cover
|
|
6219
|
+
**321 distinct predicate indicators**. Normal-mode controls and observability
|
|
6220
|
+
relations that do not belong to a library, such as `call_cleanup/2`,
|
|
6221
|
+
`setup_call_cleanup/3`, `statistics/0,2`, and `tnot/1`, are documented in their
|
|
6222
|
+
own sections rather than counted as library predicates. `time/1` is additionally
|
|
6223
|
+
registered directly in the normal runtime so Trealla-style timing works at the
|
|
6224
|
+
interactive top level without an import; it is absent from the strict ISO
|
|
6225
|
+
registry.
|
|
6224
6226
|
|
|
6225
6227
|
The sources are `src/lib/aggregate.pl`, `src/lib/arithmetic.pl`,
|
|
6226
6228
|
`src/lib/assoc.pl`, `src/lib/atts.pl`, `src/lib/between.pl`,
|
|
@@ -6256,22 +6258,33 @@ between solution branches.
|
|
|
6256
6258
|
|
|
6257
6259
|
<!-- eyeprolog-library-catalog:start -->
|
|
6258
6260
|
|
|
6259
|
-
| Module | Exported predicate indicators |
|
|
6260
|
-
| --- | --- |
|
|
6261
|
-
| `library(aggregate)` | `sumall/3`, `aggregate_min/5`, `aggregate_max/5` |
|
|
6262
|
-
| `library(
|
|
6263
|
-
| `library(
|
|
6264
|
-
| `library(
|
|
6265
|
-
| `library(
|
|
6266
|
-
| `library(
|
|
6267
|
-
|
|
|
6268
|
-
| `library(
|
|
6269
|
-
| `library(
|
|
6270
|
-
| `library(
|
|
6271
|
-
| `library(
|
|
6272
|
-
| `library(
|
|
6273
|
-
| `library(
|
|
6274
|
-
| `library(
|
|
6261
|
+
| Module | Exported predicate indicators | Primary role |
|
|
6262
|
+
| --- | --- | --- |
|
|
6263
|
+
| `library(aggregate)` | `sumall/3`, `aggregate_min/5`, `aggregate_max/5` | Aggregation |
|
|
6264
|
+
| `library(arithmetic)` | `lsb/2`, `msb/2`, `popcount/2` | CLP(Z) arithmetic support |
|
|
6265
|
+
| `library(assoc)` | `empty_assoc/1`, `assoc_to_list/2`, `get_assoc/3`, `put_assoc/4` | Association lists used by CLP(Z) |
|
|
6266
|
+
| `library(atts)` | `put_atts/2`, `get_atts/2`, `put_attr/3`, `get_attr/3`, `del_attr/2`, `term_attributed_variables/2`, `call_residue_vars/2` | Attributed variables |
|
|
6267
|
+
| `library(between)` | `between/3`, `gen_int/1`, `gen_nat/1`, `numlist/2`, `numlist/3`, `repeat/1` | Integer generation |
|
|
6268
|
+
| `library(clpz)` | `#>/2`, `#</2`, `#>=/2`, `#=</2`, `#=/2`, `#\=/2`, `#\/1`, `#<==>/2`, `#==>/2`, `#<==/2`, `#\//2`, `#\/2`, `#/\/2`, `in/2`, `ins/2`, `all_different/1`, `all_distinct/1`, `nvalue/2`, `sum/3`, `scalar_product/4`, `tuples_in/2`, `labeling/2`, `label/1`, `indomain/1`, `lex_chain/1`, `serialized/2`, `global_cardinality/2`, `global_cardinality/3`, `circuit/1`, `cumulative/1`, `cumulative/2`, `disjoint2/1`, `element/3`, `automaton/3`, `automaton/8`, `zcompare/3`, `chain/2`, `fd_var/1`, `fd_inf/2`, `fd_sup/2`, `fd_size/2`, `fd_dom/2`, `clpz_t/2`, `#=/3`, `#</3` | Constraint logic programming over integers; the final three indicators support reified compatibility libraries |
|
|
6269
|
+
| `library(comparison)` | `lt/2`, `gt/2`, `le/2`, `ge/2` | Generic comparison |
|
|
6270
|
+
| `library(dates)` | `difference/3` | ISO duration differences |
|
|
6271
|
+
| `library(dcgs)` | `phrase/2`, `phrase/3`, `seq/3`, `seqq/3` | DCG compatibility; `seq/3` and `seqq/3` are declared as `seq //1` and `seqq //1` |
|
|
6272
|
+
| `library(debug)` | `debug/1`, `debug/3`, `nodebug/1`, `bb_get/2`, `bb_b_put/2` | Scryer compatibility and backtrackable-blackboard support |
|
|
6273
|
+
| `library(error)` | `must_be/2`, `can_be/2`, `instantiation_error/0`, `instantiation_error/1`, `domain_error/2`, `domain_error/3`, `type_error/2`, `type_error/3`, `representation_error/1`, `resource_error/1`, `call_with_error_context/2` | Error checking and construction |
|
|
6274
|
+
| `library(format)` | `format/2` | Formatted output used by bundled libraries |
|
|
6275
|
+
| `library(freeze)` | `freeze/2` | Delayed goals |
|
|
6276
|
+
| `library(iso_ext)` | `call_nth/2`, `countall/2`, `forall/2`, `succ/2`, `cfor/3`, `findall/4`, `variant/2`, `time/1`, `.../2` | Common ISO extensions |
|
|
6277
|
+
| Normal runtime extension | `dif/2` | Delayed disequality; available without a library import |
|
|
6278
|
+
| `library(lambda)` | `^/3`, `^/4`, `^/5`, `^/6`, `^/7`, `^/8`, `^/9`, `^/10`, `\/1`, `\/2`, `\/3`, `\/4`, `\/5`, `\/6`, `\/7`, `\/8`, `+\/2`, `+\/3`, `+\/4`, `+\/5`, `+\/6`, `+\/7`, `+\/8`, `+\/9` | Higher-order lambda notation |
|
|
6279
|
+
| `library(lists)` | `member/2`, `memberchk/2`, `select/3`, `append/2`, `append/3`, `last/2`, `same_length/2`, `nth0/3`, `nth0/4`, `nth1/3`, `nth1/4`, `reverse/2`, `length/2`, `maplist/2`, `maplist/3`, `maplist/4`, `maplist/5`, `maplist/6`, `maplist/7`, `maplist/8`, `foldl/4`, `foldl/5`, `foldl/6`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4` | List relations |
|
|
6280
|
+
| `library(pairs)` | `pairs_keys_values/3`, `pairs_keys/2`, `pairs_values/2`, `group_pairs_by_key/2`, `map_list_to_pairs/3` | Key-value pair support |
|
|
6281
|
+
| `library(primes)` | `smallest_divisor_from/3` | Prime factor support |
|
|
6282
|
+
| `library(prologue)` | `member/2`, `append/3`, `length/2`, `between/3`, `select/3`, `succ/2`, `maplist/2`, `maplist/3`, `maplist/4`, `maplist/5`, `maplist/6`, `maplist/7`, `maplist/8`, `nth0/3`, `nth0/4`, `nth1/3`, `nth1/4`, `call_nth/2`, `freeze/2`, `foldl/4`, `foldl/5`, `foldl/6`, `countall/2` | Legacy facade over canonical focused modules |
|
|
6283
|
+
| `library(random)` | `random/3` | Pure state-threaded random generation |
|
|
6284
|
+
| `library(si)` | `atom_si/1`, `integer_si/1`, `atomic_si/1`, `list_si/1`, `character_si/1`, `term_si/1`, `chars_si/1`, `dif_si/2`, `not_si/1`, `when_si/2` | Sufficient-instantiation checks used by CLP(Z) |
|
|
6285
|
+
| `library(strings)` | `matches/3`, `split/3`, `replace/4`, `lowercase/2`, `uppercase/2`, `trim/2`, `number_string/2`, `atom_string/2`, `term_string/2`, `string_concat/3`, `contains/2`, `matches/2`, `join/3`, `substring/4` | Text relations |
|
|
6286
|
+
| `library(terms)` | `numbervars/3`, `copy_term_nat/2` | Term operations used by bundled libraries |
|
|
6287
|
+
| `library(uuid)` | `uuid/3` | Pure state-threaded UUID generation |
|
|
6275
6288
|
|
|
6276
6289
|
<!-- eyeprolog-library-catalog:end -->
|
|
6277
6290
|
|