eyeprolog 1.3.12 → 1.3.13
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 +7 -6
- package/package.json +1 -1
- package/src/iso.js +2 -2
- package/src/solver.js +16 -19
- package/src/term.js +7 -6
- package/test/run-regression.mjs +1 -1
- package/the-art-of-eyeprolog.md +145 -93
package/README.md
CHANGED
|
@@ -107,13 +107,14 @@ keeps both long-running filters such as `\+ phrase((..., Pattern), Sequence)`
|
|
|
107
107
|
and repeated same-input probes bounded without turning memory safety into a
|
|
108
108
|
per-call cache-eviction cost.
|
|
109
109
|
|
|
110
|
-
Finite-tree unification also
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
110
|
+
Finite-tree unification also accepts an internal proven-nonoccurrence hint: when
|
|
111
|
+
the solver can prove that a variable cannot occur in the value it is about to
|
|
112
|
+
receive, that binding skips an otherwise redundant occurs traversal. The main
|
|
113
|
+
source-level case is conservative first use in a freshly renamed clause, inspired
|
|
114
|
+
by the local-variable optimization used by WAM-family systems; native construction
|
|
115
|
+
paths such as relational `length/2` reuse the same unifier mechanism. Repeated
|
|
115
116
|
variables, variables seen earlier in the clause, and ordinary public unification
|
|
116
|
-
remain fully occurs-checked. This is a
|
|
117
|
+
remain fully occurs-checked. This is a proof local to one binding, not a WAM-style
|
|
117
118
|
local/global variable stack. `phrase/2` likewise supplies its fixed `[]`
|
|
118
119
|
remainder directly to the grammar; `phrase/3` retains its delayed final output
|
|
119
120
|
unification for steadfastness.
|
package/package.json
CHANGED
package/src/iso.js
CHANGED
|
@@ -181,8 +181,8 @@ export const eyePrologLibraryBuiltins = {
|
|
|
181
181
|
|
|
182
182
|
function* unification({ goal, env }) {
|
|
183
183
|
const next = env.clone();
|
|
184
|
-
const
|
|
185
|
-
if (unify(goal.args[0], goal.args[1], next, {
|
|
184
|
+
const knownNonoccurringVariables = goal._knownNonoccurringVariables ?? null;
|
|
185
|
+
if (unify(goal.args[0], goal.args[1], next, { knownNonoccurringVariables })) yield next;
|
|
186
186
|
}
|
|
187
187
|
function* unificationWithOccursCheck({ goal, env }) {
|
|
188
188
|
const next = env.clone();
|
package/src/solver.js
CHANGED
|
@@ -804,7 +804,7 @@ export class Solver {
|
|
|
804
804
|
attachBodyLocalFreshVariables(freshBody, localFreshPlan.body, freshVariables);
|
|
805
805
|
const next = env.clone();
|
|
806
806
|
this.stats.unify_calls++;
|
|
807
|
-
if (!unify(goal, freshHead, next, {
|
|
807
|
+
if (!unify(goal, freshHead, next, { knownNonoccurringVariables: headLocalFresh })) continue;
|
|
808
808
|
if (freshBody.length === 0) {
|
|
809
809
|
yield* this.solve(rest, next, depth + 1);
|
|
810
810
|
} else if (!groupNeedsActiveFrame(group)) {
|
|
@@ -1021,7 +1021,7 @@ function pushUserGoalUncachedFrames(stack, solver, group, goal, rest, env, depth
|
|
|
1021
1021
|
attachBodyLocalFreshVariables(freshBody, localFreshPlan.body, freshVariables);
|
|
1022
1022
|
const next = env.clone();
|
|
1023
1023
|
solver.stats.unify_calls++;
|
|
1024
|
-
if (!unify(goal, freshHead, next, {
|
|
1024
|
+
if (!unify(goal, freshHead, next, { knownNonoccurringVariables: headLocalFresh })) continue;
|
|
1025
1025
|
if (freshBody.length === 0) {
|
|
1026
1026
|
frames.push({
|
|
1027
1027
|
kind: 'goals',
|
|
@@ -1083,10 +1083,10 @@ function freshVariableSet(names, freshVariables) {
|
|
|
1083
1083
|
|
|
1084
1084
|
function attachBodyLocalFreshVariables(freshBody, plan, freshVariables) {
|
|
1085
1085
|
for (let index = 0; index < freshBody.length; index++) {
|
|
1086
|
-
const
|
|
1087
|
-
if (
|
|
1086
|
+
const knownNonoccurringVariables = freshVariableSet(plan[index] ?? [], freshVariables);
|
|
1087
|
+
if (knownNonoccurringVariables != null && freshBody[index]?.type === COMPOUND &&
|
|
1088
1088
|
freshBody[index].name === '=' && freshBody[index].arity === 2) {
|
|
1089
|
-
freshBody[index].
|
|
1089
|
+
freshBody[index]._knownNonoccurringVariables = knownNonoccurringVariables;
|
|
1090
1090
|
}
|
|
1091
1091
|
}
|
|
1092
1092
|
}
|
|
@@ -1257,12 +1257,11 @@ function* fixedLengthSolutions(solver, list, length, env) {
|
|
|
1257
1257
|
const suffix = compactVariableList(remaining, `__length${id}_`);
|
|
1258
1258
|
const next = env.clone();
|
|
1259
1259
|
solver.stats.unify_calls++;
|
|
1260
|
-
//
|
|
1261
|
-
//
|
|
1262
|
-
//
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
yield next;
|
|
1260
|
+
// The compact skeleton contains only freshly generated variables, so the
|
|
1261
|
+
// dereferenced tail variable is known not to occur in it. Reuse the same
|
|
1262
|
+
// proven-nonoccurrence path as source-level first-use unification.
|
|
1263
|
+
const knownNonoccurringVariables = new Set([cursor.name]);
|
|
1264
|
+
if (unify(cursor, suffix, next, { knownNonoccurringVariables })) yield next;
|
|
1266
1265
|
}
|
|
1267
1266
|
|
|
1268
1267
|
function* generatedLengthSolutions(solver, list, length, env) {
|
|
@@ -1296,15 +1295,13 @@ function* generatedLengthSolutions(solver, list, length, env) {
|
|
|
1296
1295
|
|
|
1297
1296
|
const id = nextFreshId();
|
|
1298
1297
|
let suffix = emptyList();
|
|
1298
|
+
// Every generated suffix is built from fresh variables and therefore cannot
|
|
1299
|
+
// contain the caller's dereferenced tail variable. Share the general
|
|
1300
|
+
// proven-nonoccurrence unification path instead of bypassing unify() here.
|
|
1301
|
+
const knownNonoccurringVariables = new Set([cursor.name]);
|
|
1299
1302
|
for (let extra = 0n; ; extra++) {
|
|
1300
1303
|
const next = env.clone();
|
|
1301
|
-
|
|
1302
|
-
// freshly generated variables, so this binding cannot create a cycle.
|
|
1303
|
-
// Binding directly avoids an O(extra) occurs-check over the complete
|
|
1304
|
-
// growing suffix for every answer; without this, unbounded length/2
|
|
1305
|
-
// generation becomes quadratic and can spend hours before reaching the
|
|
1306
|
-
// normal memory resource guard (issue #49).
|
|
1307
|
-
next.bind(cursor.name, suffix);
|
|
1304
|
+
if (!unify(cursor, suffix, next, { knownNonoccurringVariables })) return;
|
|
1308
1305
|
const answer = bindGeneratedLength(solver, length, count + extra, next);
|
|
1309
1306
|
if (answer != null) yield answer;
|
|
1310
1307
|
suffix = cons(variable(`__length${id}_${extra}`), suffix);
|
|
@@ -2395,7 +2392,7 @@ function selectReadyDeterministicBuiltin(goals, env, registry) {
|
|
|
2395
2392
|
// A first-use proof is derived from source goal order. Do not move a later
|
|
2396
2393
|
// deterministic builtin across that equality: doing so could touch one of
|
|
2397
2394
|
// its proven-fresh variables before the checked binding executes.
|
|
2398
|
-
if (goal?.
|
|
2395
|
+
if (goal?._knownNonoccurringVariables != null) return 0;
|
|
2399
2396
|
if (goal.type !== COMPOUND && goal.type !== 'atom') continue;
|
|
2400
2397
|
const def = registry.get(goal.name, goal.arity);
|
|
2401
2398
|
if (!def?.deterministic || typeof def.ready !== 'function') continue;
|
package/src/term.js
CHANGED
|
@@ -271,10 +271,11 @@ export function unify(left, right, env, options = {}) {
|
|
|
271
271
|
// unification: a variable cannot be bound to a term containing itself.
|
|
272
272
|
// Bindings are written into the supplied Env.
|
|
273
273
|
const occursCheckHandler = options.occursCheck === 'fail' ? null : env?._occursCheckHandler;
|
|
274
|
-
//
|
|
275
|
-
// term
|
|
276
|
-
//
|
|
277
|
-
|
|
274
|
+
// Callers may provide a proof that selected variables cannot occur in the
|
|
275
|
+
// term they are about to receive. Source-level first-use analysis and a few
|
|
276
|
+
// construction fast paths share this internal proof; ordinary unification
|
|
277
|
+
// remains fully occurs-checked.
|
|
278
|
+
const knownNonoccurringVariables = options.knownNonoccurringVariables ?? null;
|
|
278
279
|
const stack = [[left, right]];
|
|
279
280
|
while (stack.length) {
|
|
280
281
|
let [a, b] = stack.pop();
|
|
@@ -290,7 +291,7 @@ export function unify(left, right, env, options = {}) {
|
|
|
290
291
|
continue;
|
|
291
292
|
}
|
|
292
293
|
if (a.type === VAR) {
|
|
293
|
-
if (!
|
|
294
|
+
if (!knownNonoccurringVariables?.has(a.name) && occurs(a.name, b, env)) {
|
|
294
295
|
occursCheckHandler?.(a, b, env);
|
|
295
296
|
return false;
|
|
296
297
|
}
|
|
@@ -299,7 +300,7 @@ export function unify(left, right, env, options = {}) {
|
|
|
299
300
|
continue;
|
|
300
301
|
}
|
|
301
302
|
if (b.type === VAR) {
|
|
302
|
-
if (!
|
|
303
|
+
if (!knownNonoccurringVariables?.has(b.name) && occurs(b.name, a, env)) {
|
|
303
304
|
occursCheckHandler?.(b, a, env);
|
|
304
305
|
return false;
|
|
305
306
|
}
|
package/test/run-regression.mjs
CHANGED
|
@@ -1318,7 +1318,7 @@ c4 ?- call((!;1)).
|
|
|
1318
1318
|
},
|
|
1319
1319
|
},
|
|
1320
1320
|
{
|
|
1321
|
-
name: 'first-use
|
|
1321
|
+
name: 'proven-nonoccurrence first-use shortcut preserves finite-tree occurs checking',
|
|
1322
1322
|
run: () => {
|
|
1323
1323
|
const program = Program.parse(`
|
|
1324
1324
|
first_use_cycle :- X = f(Y), Y = g(X).
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -1900,14 +1900,16 @@ unification, another list predicate, or answer readback inspects it. This is a
|
|
|
1900
1900
|
storage optimization, not a distinct Prolog term or list semantics. Embedders
|
|
1901
1901
|
that inspect the JavaScript term model can recognize this representation with
|
|
1902
1902
|
`CompactListTerm`, `isCompactList`, and `compactListLength`, or construct one
|
|
1903
|
-
with `compactVariableList`. For open-ended `length(List, N)` generation,
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1903
|
+
with `compactVariableList`. For open-ended `length(List, N)` generation, each generated spine is known not
|
|
1904
|
+
to contain the caller's dereferenced tail variable. The bundled path passes that
|
|
1905
|
+
proof through the normal unifier, sharing the same proven-nonoccurrence mechanism
|
|
1906
|
+
as first-use clause variables instead of maintaining a predicate-specific raw
|
|
1907
|
+
binding shortcut. It still reserves recovery headroom proportional to the
|
|
1908
|
+
retained spine, so a finite heap limit is raised inside the `length/2` search as
|
|
1909
|
+
a catchable `resource_error(memory)` rather than allowing an outer solver frame
|
|
1910
|
+
to encounter the limit first.
|
|
1911
|
+
|
|
1912
|
+
The same proven-nonoccurrence mechanism has a conservative source-level form for freshly renamed
|
|
1911
1913
|
clauses. A singleton variable in the clause head, or a variable that has not
|
|
1912
1914
|
appeared in the head or any earlier body goal and occurs exactly once in a
|
|
1913
1915
|
direct `=/2` goal, cannot already be a subterm of the value it is about to
|
|
@@ -6121,47 +6123,74 @@ between solution branches.
|
|
|
6121
6123
|
|
|
6122
6124
|
#### Interoperability profile and conservative autoloading
|
|
6123
6125
|
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
`library(
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
`library(
|
|
6151
|
-
|
|
6126
|
+
EyeProlog keeps four related concepts separate:
|
|
6127
|
+
|
|
6128
|
+
| Layer | Meaning |
|
|
6129
|
+
| --- | --- |
|
|
6130
|
+
| **ISO core** | The documented ISO predicate profile built into the processor. No EyeProlog library import is involved. |
|
|
6131
|
+
| **EyeProlog library surface** | Every module and exported predicate listed in the catalog above. Programs normally access these with `use_module/1-2`. |
|
|
6132
|
+
| **Interoperability profile** | A deliberately smaller set of library names and predicate interfaces that EyeProlog intends to keep source-compatible with Trealla and Scryer where practical. |
|
|
6133
|
+
| **Autoload map** | An even smaller convenience table that gives selected unqualified predicates one canonical EyeProlog provider. |
|
|
6134
|
+
|
|
6135
|
+
These layers answer different questions. A predicate may be implemented entirely
|
|
6136
|
+
as ordinary Prolog and still be outside the cross-processor interoperability
|
|
6137
|
+
profile; conversely, an interoperable predicate may be backed by a private host
|
|
6138
|
+
adapter. In this section, **portable** refers to source portability between
|
|
6139
|
+
Prolog systems, not merely to the language in which a predicate happens to be
|
|
6140
|
+
implemented.
|
|
6141
|
+
|
|
6142
|
+
The current interoperability profile recognizes these library roles:
|
|
6143
|
+
|
|
6144
|
+
| Library | Role in the interoperability profile |
|
|
6145
|
+
| --- | --- |
|
|
6146
|
+
| `library(lists)` | Common list module. A conservative subset of its exports is in the shared predicate profile. |
|
|
6147
|
+
| `library(iso_ext)` | Common extension-module name. `call_nth/2` is currently its autoloaded cross-engine predicate. |
|
|
6148
|
+
| `library(lambda)` | Scryer-aligned higher-order notation. It is imported explicitly because loading it also installs the `+\` operator. |
|
|
6149
|
+
| `library(prologue)` | EyeProlog compatibility module, not a common interop library name. `between/3` is nevertheless autoloaded from it so portable source need not name this EyeProlog-specific provider. |
|
|
6150
|
+
|
|
6151
|
+
Other modules from the catalog, including `library(clpz)`, `library(strings)`,
|
|
6152
|
+
`library(random)`, and `library(uuid)`, remain normal EyeProlog libraries. They
|
|
6153
|
+
can be imported explicitly, but their module names and full APIs are not thereby
|
|
6154
|
+
claimed as part of the current conservative Trealla/Scryer profile.
|
|
6155
|
+
|
|
6156
|
+
For `library(lists)`, the current interop predicate set is `member/2`,
|
|
6157
|
+
`memberchk/2`, `select/3`, `append/2-3`, `last/2`, `same_length/2`,
|
|
6158
|
+
`nth0/3-4`, `nth1/3-4`, `reverse/2`, `length/2`, `maplist/2-8`,
|
|
6159
|
+
`foldl/4-6`, `sum_list/2`, and `list_to_set/2`. Other exports from the same
|
|
6160
|
+
module, such as `min_list/2`, `max_list/2`, `set_nth0/4`, `take/3`, `drop/3`,
|
|
6161
|
+
and `slice/4`, remain available to EyeProlog programs but lie outside this
|
|
6162
|
+
conservative cross-engine subset.
|
|
6163
|
+
|
|
6164
|
+
`length/2` remains fully relational. With both arguments variable,
|
|
6165
|
+
`length(Xs, N)` enumerates `Xs = [], N = 0`, then one-element lists with
|
|
6166
|
+
`N = 1`, and so on. Open-ended generation uses the normal memory guard with
|
|
6167
|
+
recovery headroom so finite-heap exhaustion remains a catchable
|
|
6168
|
+
`resource_error(memory)`.
|
|
6169
|
+
|
|
6170
|
+
`library(iso_ext)` is a common interop module name, but only part of its
|
|
6171
|
+
EyeProlog API belongs to the shared profile. `call_nth/2` is mapped there to
|
|
6172
|
+
match Scryer's explicit import organization while also permitting portable
|
|
6173
|
+
unqualified source to autoload it. The interop exports of `library(lists)` and
|
|
6174
|
+
`library(iso_ext)` are kept disjoint, so both modules can be imported together
|
|
6175
|
+
without an accidental collision. `library(prologue)` remains a compatibility
|
|
6176
|
+
umbrella and overlaps them; use selective imports when legacy code combines it
|
|
6177
|
+
with the aligned modules.
|
|
6178
|
+
|
|
6179
|
+
`library(lambda)` follows Scryer's higher-order notation, adapted from Ulrich
|
|
6180
|
+
Neumerkel's permissively licensed implementation. Its public syntax is:
|
|
6152
6181
|
|
|
6153
6182
|
```text
|
|
6154
6183
|
\X1^X2^...^XN^Goal
|
|
6155
6184
|
Free+\X1^X2^...^XN^Goal
|
|
6156
6185
|
```
|
|
6157
6186
|
|
|
6158
|
-
The first form has no explicitly shared free variables. Before each invocation
|
|
6159
|
-
EyeProlog copies the closure term
|
|
6187
|
+
The first form has no explicitly shared free variables. Before each invocation,
|
|
6188
|
+
EyeProlog copies the closure term so local variables are fresh on successive
|
|
6160
6189
|
`maplist/2-8`, `foldl/4-6`, or direct `call/N` uses. In the second form, the
|
|
6161
|
-
variables contained in `Free` remain shared with the surrounding goal.
|
|
6162
|
-
the library installs `+\` as a priority-201 `xfx` operator; `\` and
|
|
6163
|
-
their existing ISO operator definitions. Parenthesize lower-priority
|
|
6164
|
-
operators after `^`, for example `\X^(X > 3)`.
|
|
6190
|
+
variables contained in `Free` remain shared with the surrounding goal.
|
|
6191
|
+
Importing the library installs `+\` as a priority-201 `xfx` operator; `\` and
|
|
6192
|
+
`^` use their existing ISO operator definitions. Parenthesize lower-priority
|
|
6193
|
+
goal operators after `^`, for example `\X^(X > 3)`.
|
|
6165
6194
|
|
|
6166
6195
|
A continuation lambda may leave arguments for a later call:
|
|
6167
6196
|
|
|
@@ -6171,56 +6200,78 @@ f(x, y).
|
|
|
6171
6200
|
answer(A, B) :- call(\X^f(X), A, B).
|
|
6172
6201
|
```
|
|
6173
6202
|
|
|
6174
|
-
This is equivalent to supplying both arguments directly. A lambda
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
`
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
only when the interop table assigns it one canonical provider.
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6203
|
+
This is equivalent to supplying both arguments directly. A lambda called with
|
|
6204
|
+
too few parameters raises `existence_error(lambda_parameter, ...)`. EyeProlog
|
|
6205
|
+
uses its ISO `copy_term/2` implementation for the fresh-copy step and does not
|
|
6206
|
+
require a separate `copy_term_nat/2` predicate.
|
|
6207
|
+
|
|
6208
|
+
Autoloading is a convenience layered on top of the interoperability profile; it
|
|
6209
|
+
is not a general search through all EyeProlog libraries. During normal
|
|
6210
|
+
execution, an otherwise undefined **unqualified** predicate may be autoloaded
|
|
6211
|
+
only when the interop table assigns it one canonical provider. For example:
|
|
6212
|
+
|
|
6213
|
+
| Predicate | Canonical autoload provider |
|
|
6214
|
+
| --- | --- |
|
|
6215
|
+
| `member/2` | `library(lists)` |
|
|
6216
|
+
| `call_nth/2` | `library(iso_ext)` |
|
|
6217
|
+
| `between/3` | `library(prologue)` |
|
|
6218
|
+
|
|
6219
|
+
Predicates outside that table require an explicit import even when EyeProlog
|
|
6220
|
+
provides them. Explicit imports therefore remain the clearest way to state
|
|
6221
|
+
library dependencies:
|
|
6222
|
+
|
|
6223
|
+
```text
|
|
6224
|
+
:- use_module(library(lists)).
|
|
6225
|
+
:- use_module(library(iso_ext), [call_nth/2]).
|
|
6226
|
+
```
|
|
6227
|
+
|
|
6228
|
+
Use `--no-autoload`, or the JavaScript option `autoload: false`, when every
|
|
6229
|
+
library dependency should be explicit. `--iso-strict` always disables EyeProlog
|
|
6230
|
+
library autoloading.
|
|
6231
|
+
|
|
6232
|
+
`-w` / `--warnings` reports explicit dependencies on non-profile libraries and
|
|
6233
|
+
calls to non-profile predicates from otherwise common modules. `--portable`
|
|
6234
|
+
turns those diagnostics into a failing run, making the conservative profile
|
|
6235
|
+
suitable for continuous integration. `npm run test:interop` executes the same
|
|
6236
|
+
portable Sudoku source under EyeProlog, Trealla, and Scryer when those commands
|
|
6237
|
+
are installed; the repository interoperability workflow installs them and runs
|
|
6238
|
+
that check.
|
|
6239
|
+
|
|
6240
|
+
#### Library notes beyond the interoperability profile
|
|
6241
|
+
|
|
6242
|
+
The catalog above is authoritative for the complete EyeProlog library surface.
|
|
6243
|
+
The following notes describe useful parts of that surface without extending the
|
|
6244
|
+
cross-engine claims made above.
|
|
6245
|
+
|
|
6246
|
+
`library(clpz)` follows the familiar Trealla and Scryer convention for
|
|
6247
|
+
constraint logic programming over integers. EyeProlog currently provides finite
|
|
6197
6248
|
interval and union domains, arithmetic and reified constraints, backtrackable
|
|
6198
|
-
labeling with `ff`, `up`, and `down`, global distinctness, linear sums and
|
|
6199
|
-
|
|
6249
|
+
labeling with `ff`, `up`, and `down`, global distinctness, linear sums and scalar
|
|
6250
|
+
products, chains, elements, value counting, extensional tuple tables,
|
|
6200
6251
|
lexicographic chains, serialized schedules, global cardinality with costs,
|
|
6201
6252
|
Hamiltonian circuits, three-way comparison, and domain reflection. Constraints
|
|
6202
6253
|
are kept in the logical environment, so failed alternatives cannot leak domains
|
|
6203
|
-
into later branches.
|
|
6204
|
-
cumulative and two-dimensional scheduling constraints, and
|
|
6205
|
-
propagation that
|
|
6206
|
-
|
|
6207
|
-
`library(iso_ext)`
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6216
|
-
|
|
6217
|
-
`uuid(+Seed0,-UUID,-Seed)` creates a version 4 UUID atom
|
|
6218
|
-
Passing the returned seed to the next call produces the next
|
|
6219
|
-
with the same integer seed reproduces the same sequence
|
|
6220
|
-
state replaces hidden host entropy and behaves identically in Node and
|
|
6221
|
-
browser playground.
|
|
6222
|
-
|
|
6223
|
-
On the command line, a program
|
|
6254
|
+
into later branches. Trealla's larger library also contains facilities such as
|
|
6255
|
+
automata, cumulative and two-dimensional scheduling constraints, and
|
|
6256
|
+
unbounded-domain propagation that EyeProlog does not currently export.
|
|
6257
|
+
|
|
6258
|
+
Beyond its interop entry for `call_nth/2`, `library(iso_ext)` also exports
|
|
6259
|
+
EyeProlog's extension relations `countall/2`, `forall/2`, `succ/2`, `cfor/3`,
|
|
6260
|
+
`findall/4`, and `variant/2`. `forall/2` checks an action for every solution of a
|
|
6261
|
+
condition; `cfor/3` enumerates an inclusive evaluated integer range; `succ/2`
|
|
6262
|
+
relates adjacent nonnegative integers; `findall/4` collects into a difference
|
|
6263
|
+
list; and `variant/2` recognizes terms equal up to variable renaming.
|
|
6264
|
+
`countall/2` counts solutions without exposing a template. These exports do not
|
|
6265
|
+
all belong to the conservative interop subset merely because they share the
|
|
6266
|
+
`iso_ext` module.
|
|
6267
|
+
|
|
6268
|
+
`uuid(+Seed0,-UUID,-Seed)` from `library(uuid)` creates a version 4 UUID atom
|
|
6269
|
+
using `random/3`. Passing the returned seed to the next call produces the next
|
|
6270
|
+
UUID; restarting with the same integer seed reproduces the same sequence. This
|
|
6271
|
+
explicit state replaces hidden host entropy and behaves identically in Node and
|
|
6272
|
+
the browser playground.
|
|
6273
|
+
|
|
6274
|
+
On the command line, a program can state its library dependencies explicitly:
|
|
6224
6275
|
|
|
6225
6276
|
```sh
|
|
6226
6277
|
printf '%s\n' ':- use_module(library(lists)).' 'answer(X) :- member(X, [ready]).' > program.pl
|
|
@@ -6228,12 +6279,13 @@ eyeprolog --goal 'answer(X)' program.pl
|
|
|
6228
6279
|
eyeprolog -p program.pl # add proof output
|
|
6229
6280
|
```
|
|
6230
6281
|
|
|
6231
|
-
JavaScript uses the same registry by default:
|
|
6282
|
+
JavaScript uses the same normal EyeProlog library registry by default:
|
|
6232
6283
|
|
|
6233
6284
|
```js
|
|
6234
6285
|
import { run } from 'eyeprolog';
|
|
6235
6286
|
|
|
6236
6287
|
const source = `
|
|
6288
|
+
:- use_module(library(lists)).
|
|
6237
6289
|
answer(Whole) :- append([red, green], [blue], Whole).
|
|
6238
6290
|
`;
|
|
6239
6291
|
|
|
@@ -6241,7 +6293,7 @@ const result = run(source, { goal: 'answer(X)' });
|
|
|
6241
6293
|
console.log(result.stdout);
|
|
6242
6294
|
```
|
|
6243
6295
|
|
|
6244
|
-
The mode notation below is descriptive:
|
|
6296
|
+
The mode notation used in the reference tables below is descriptive:
|
|
6245
6297
|
|
|
6246
6298
|
- `+` means the argument must already have the required input shape;
|
|
6247
6299
|
- `-` means the predicate produces that argument;
|
|
@@ -6250,9 +6302,9 @@ The mode notation below is descriptive:
|
|
|
6250
6302
|
Most EyeProlog library predicates are projections or filters. When an input is
|
|
6251
6303
|
unbound, malformed, outside its domain, or incompatible with the requested
|
|
6252
6304
|
output, they normally **fail** rather than raising the ISO errors described in
|
|
6253
|
-
the errors section above. They do not invent open-ended domains. Bind arithmetic
|
|
6254
|
-
text, proper lists, indexes, dates, and aggregate generators
|
|
6255
|
-
the corresponding predicate.
|
|
6305
|
+
the errors section above. They do not invent open-ended domains. Bind arithmetic
|
|
6306
|
+
operands, source text, proper lists, indexes, dates, and aggregate generators
|
|
6307
|
+
before calling the corresponding predicate.
|
|
6256
6308
|
|
|
6257
6309
|
#### Portable numeric, comparison, and date relations
|
|
6258
6310
|
|