eyeprolog 1.5.12 → 1.5.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 CHANGED
@@ -61,7 +61,7 @@ Normal mode executes top-level `Conclusion :+ Premise` rules through the bundled
61
61
 
62
62
  Bundled `src/lib/` predicates autoload in files, CLI/API goals, and the REPL; use `--no-autoload` to require explicit imports, and explicitly import libraries that introduce operators before using their syntax. See [*The Art of EyeProlog*](the-art-of-eyeprolog.md) for the full semantics.
63
63
 
64
- All 32 bundled modules that overlap Scryer's current `src/lib/` surface now cover Scryer's exported predicates, while the stricter Trealla/Scryer intersection remains a separate portability profile. Runtime-dependent library primitives follow one ownership rule: `src/lib/<module>.pl` calls private adapters from `src/<module>-host.js`; pure Prolog libraries need no host file. This includes the full Scryer `library(files)` surface, Scryer character-list paths in `library(pio)` with atom-path compatibility, chars/UTF-8/term/Base64 helpers, the completed arithmetic/time/`iso_ext` surfaces, and the full Scryer `library(crypto)`. Filesystem and OS side effects require Node; crypto uses Node's backend where needed, with Web Crypto also used for secure random bytes when available. Non-integral rational conversions remain structural `rdiv(Numerator,Denominator)` terms until rational numbers become processor numeric values.
64
+ All 32 bundled modules that overlap Scryer's current `src/lib/` surface cover Scryer's exported predicates, and all 26 bundled modules with public-module counterparts in Trealla's current `library/` surface cover those Trealla exports as well. The stricter Trealla/Scryer intersection remains a separate portability profile. Runtime-dependent library primitives follow one ownership rule: `src/lib/<module>.pl` calls private adapters from `src/<module>-host.js`; pure Prolog libraries need no host file. This includes the full Scryer `library(files)` surface, Scryer character-list paths in `library(pio)` with atom-path compatibility, chars/UTF-8/term/Base64 helpers, the completed arithmetic/time/`iso_ext` surfaces, and the full Scryer `library(crypto)`. Filesystem and OS side effects require Node; crypto uses Node's backend where needed, with Web Crypto also used for secure random bytes when available. Non-integral rational conversions remain structural `rdiv(Numerator,Denominator)` terms until rational numbers become processor numeric values.
65
65
 
66
66
  ## Links
67
67
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.5.12",
6
+ "version": "1.5.13",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -1,8 +1,17 @@
1
1
  /** Portable solution aggregation relations. */
2
2
 
3
- :- module(aggregate, [sumall/3, aggregate_min/5, aggregate_max/5]).
3
+ /* Trealla-compatible aggregate_all/3 and aggregate/3 behavior is adapted
4
+ from Trealla Prolog library/aggregate.pl (MIT),
5
+ Copyright (c) 2020 Andrew George Davison. */
6
+
7
+ :- module(aggregate, [
8
+ sumall/3, aggregate_min/5, aggregate_max/5,
9
+ aggregate_all/3, aggregate/3
10
+ ]).
4
11
 
5
12
  :- meta_predicate(sumall('?', 0, '?')).
13
+ :- meta_predicate(aggregate_all('?', 0, '?')).
14
+ :- meta_predicate(aggregate('?', 0, '?')).
6
15
  :- meta_predicate(aggregate_min('?', '?', 0, '?', '?')).
7
16
  :- meta_predicate(aggregate_max('?', '?', 0, '?', '?')).
8
17
 
@@ -31,3 +40,71 @@ aggregate__reverse([X|Xs], Acc, Out) :- aggregate__reverse(Xs, [X|Acc], Out).
31
40
  aggregate__last_pair([Pair], Pair).
32
41
  aggregate__last_pair([_|Pairs], Pair) :- aggregate__last_pair(Pairs, Pair).
33
42
 
43
+
44
+ % Trealla-compatible aggregate templates. These are source-level relations;
45
+ % EyeProlog keeps its older sumall/3 and aggregate_min/max helpers alongside
46
+ % them for backward compatibility.
47
+ aggregate_all(Aggregate, Goal, Result) :-
48
+ aggregate__init(Aggregate, Template, Initial),
49
+ findall(Template, Goal, Values),
50
+ aggregate__compute(Values, Aggregate, Initial, Result).
51
+
52
+ aggregate(Aggregate, Goal, Result) :-
53
+ aggregate__init(Aggregate, Template, Initial),
54
+ bagof(Template, Goal, Values),
55
+ aggregate__compute(Values, Aggregate, Initial, Result).
56
+
57
+ aggregate__compute([], Aggregate, Initial, Result) :-
58
+ aggregate__finish(Aggregate, Initial, Result).
59
+ aggregate__compute([Value|Values], Aggregate, Acc0, Result) :-
60
+ aggregate__next(Aggregate, Acc0, Value, Acc),
61
+ aggregate__compute(Values, Aggregate, Acc, Result).
62
+
63
+ aggregate__init(Aggregate, _, _) :- var(Aggregate), !,
64
+ throw(error(instantiation_error, aggregate/3)).
65
+ aggregate__init(count, '', 0) :- !.
66
+ aggregate__init(sum(X), X, 0) :- !.
67
+ aggregate__init(mul(X), X, 1) :- !.
68
+ aggregate__init(min(X), X, sup) :- !.
69
+ aggregate__init(max(X), X, inf) :- !.
70
+ aggregate__init(bag(X), X, []) :- !.
71
+ aggregate__init(set(X), X, []) :- !.
72
+ aggregate__init((F,G), (X,Y), (A,B)) :- !,
73
+ aggregate__init(F, X, A),
74
+ aggregate__init(G, Y, B).
75
+ aggregate__init(Aggregate, _, _) :-
76
+ throw(error(type_error(aggregate, Aggregate), aggregate/3)).
77
+
78
+ aggregate__next(count, A, '', C) :- C is A + 1.
79
+ aggregate__next(sum(_), A, B, C) :- C is A + B.
80
+ aggregate__next(mul(_), A, B, C) :- C is A * B.
81
+ aggregate__next(min(_), A, B, C) :- aggregate__min(A, B, C).
82
+ aggregate__next(max(_), A, B, C) :- aggregate__max(A, B, C).
83
+ aggregate__next(bag(_), A, B, [B|A]).
84
+ aggregate__next(set(_), A, B, [B|A]).
85
+ aggregate__next((F,G), (A,B), (X,Y), (C,D)) :-
86
+ aggregate__next(F, A, X, C),
87
+ aggregate__next(G, B, Y, D).
88
+
89
+ aggregate__finish(count, A, A).
90
+ aggregate__finish(sum(_), A, A).
91
+ aggregate__finish(mul(_), A, A).
92
+ aggregate__finish(min(_), A, A).
93
+ aggregate__finish(max(_), A, A).
94
+ aggregate__finish(bag(_), A, B) :- aggregate__reverse(A, [], B).
95
+ aggregate__finish(set(_), A, B) :- aggregate__reverse(A, [], R), sort(R, B).
96
+ aggregate__finish((F,G), (X,Y), (A,B)) :-
97
+ aggregate__finish(F, X, A),
98
+ aggregate__finish(G, Y, B).
99
+
100
+ aggregate__min(sup, X, X) :- !.
101
+ aggregate__min(X, sup, X) :- !.
102
+ aggregate__min(inf, _, inf) :- !.
103
+ aggregate__min(_, inf, inf) :- !.
104
+ aggregate__min(X, Y, R) :- R is min(X, Y).
105
+
106
+ aggregate__max(inf, X, X) :- !.
107
+ aggregate__max(X, inf, X) :- !.
108
+ aggregate__max(sup, _, sup) :- !.
109
+ aggregate__max(_, sup, sup) :- !.
110
+ aggregate__max(X, Y, R) :- R is max(X, Y).
package/src/lib/error.pl CHANGED
@@ -11,6 +11,7 @@
11
11
  type_error/3,
12
12
  representation_error/1,
13
13
  resource_error/1,
14
+ resource_error/2,
14
15
  call_with_error_context/2
15
16
  ]).
16
17
 
@@ -118,6 +119,7 @@ type_error(Type, Term) :- throw(error(type_error(Type, Term), [])).
118
119
  type_error(Type, Term, Context) :- throw(error(type_error(Type, Term), Context)).
119
120
  representation_error(Flag) :- throw(error(representation_error(Flag), [])).
120
121
  resource_error(Resource) :- throw(error(resource_error(Resource), [])).
122
+ resource_error(Resource, Context) :- throw(error(resource_error(Resource), Context)).
121
123
 
122
124
  call_with_error_context(Goal, Pair) :-
123
125
  catch(Goal, error(Error, Context), throw(error(Error, [Pair|Context]))).
package/src/lib/freeze.pl CHANGED
@@ -1,8 +1,9 @@
1
- /** Attributed-variable implementation of Scryer-compatible freeze/2. */
1
+ /** Attributed-variable freeze/2 plus Trealla-compatible frozen/2 inspection. */
2
2
 
3
- :- module(freeze, [freeze/2]).
3
+ :- module(freeze, [freeze/2, frozen/2]).
4
4
 
5
5
  :- use_module(library(atts)).
6
+ :- use_module(library(iso_ext), [copy_term/3]).
6
7
  :- meta_predicate(freeze(-, 0)).
7
8
  :- attribute frozen/1.
8
9
 
@@ -27,6 +28,23 @@ freeze(X, Goal) :-
27
28
  put_atts(Fresh, frozen(frozen_goal(Goal))),
28
29
  Fresh = X.
29
30
 
31
+ % Trealla-compatible frozen/2. copy_term/3 already projects both native and
32
+ % Prolog-defined attributed-variable residual goals. Re-unifying the fresh
33
+ % structural copy aliases those projected variables back to Term without
34
+ % instantiating them, so Goal describes the suspensions on the original term.
35
+ frozen(Term, Goal) :-
36
+ copy_term(Term, Copy, Goals),
37
+ Term = Copy,
38
+ freeze__goals_conjunction(Goals, Goal).
39
+
40
+ freeze__goals_conjunction([], true).
41
+ freeze__goals_conjunction([Goal|Goals], Conjunction) :-
42
+ freeze__goals_conjunction_(Goals, Goal, Conjunction).
43
+
44
+ freeze__goals_conjunction_([], Goal, Goal).
45
+ freeze__goals_conjunction_([Goal|Goals], Acc, Conjunction) :-
46
+ freeze__goals_conjunction_(Goals, (Acc, Goal), Conjunction).
47
+
30
48
  frozen_goals(Frozen, Goals) :-
31
49
  frozen_goals(Frozen, Goals, []).
32
50
 
package/src/lib/lists.pl CHANGED
@@ -4,6 +4,11 @@
4
4
  member/2,
5
5
  memberchk/2,
6
6
  select/3,
7
+ selectchk/3,
8
+ subtract/3,
9
+ union/3,
10
+ intersection/3,
11
+ is_set/1,
7
12
  append/2,
8
13
  append/3,
9
14
  last/2,
@@ -14,6 +19,8 @@
14
19
  nth1/4,
15
20
  reverse/2,
16
21
  length/2,
22
+ exclude/3,
23
+ include/3,
17
24
  maplist/2,
18
25
  maplist/3,
19
26
  maplist/4,
@@ -22,6 +29,13 @@
22
29
  maplist/7,
23
30
  maplist/8,
24
31
  maplist/9,
32
+ tasklist/2,
33
+ tasklist/3,
34
+ tasklist/4,
35
+ tasklist/5,
36
+ tasklist/6,
37
+ tasklist/7,
38
+ tasklist/8,
25
39
  foldl/4,
26
40
  foldl/5,
27
41
  foldl/6,
@@ -50,6 +64,16 @@
50
64
  :- meta_predicate(foldl(3, '?', '?', '?')).
51
65
  :- meta_predicate(foldl(4, '?', '?', '?', '?')).
52
66
  :- meta_predicate(foldl(5, '?', '?', '?', '?', '?')).
67
+ :- meta_predicate(include(1, '?', '?')).
68
+ :- meta_predicate(exclude(1, '?', '?')).
69
+ :- meta_predicate(tasklist(1, '?')).
70
+ :- meta_predicate(tasklist(2, '?', '?')).
71
+ :- meta_predicate(tasklist(3, '?', '?', '?')).
72
+ :- meta_predicate(tasklist(4, '?', '?', '?', '?')).
73
+ :- meta_predicate(tasklist(5, '?', '?', '?', '?', '?')).
74
+ :- meta_predicate(tasklist(6, '?', '?', '?', '?', '?', '?')).
75
+ :- meta_predicate(tasklist(7, '?', '?', '?', '?', '?', '?', '?')).
76
+
53
77
 
54
78
  % Common pure-Prolog library predicates for EyeProlog.
55
79
  %
@@ -99,6 +123,27 @@ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs], [G|Gs], [H|Hs])
99
123
  eyeprolog__call8(Closure, A, B, C, D, E, F, G, H),
100
124
  maplist(Closure, As, Bs, Cs, Ds, Es, Fs, Gs, Hs).
101
125
 
126
+ include(_, [], []).
127
+ include(Predicate, [X|Xs], Included) :-
128
+ ( call(Predicate, X) -> Included = [X|Rest] ; Included = Rest ),
129
+ include(Predicate, Xs, Rest).
130
+
131
+ exclude(_, [], []).
132
+ exclude(Predicate, [X|Xs], Excluded) :-
133
+ ( call(Predicate, X) -> Excluded = Rest ; Excluded = [X|Rest] ),
134
+ exclude(Predicate, Xs, Rest).
135
+
136
+ % Trealla runs tasklist/* items through its task scheduler. EyeProlog has no
137
+ % task scheduler, so the compatibility surface deliberately uses deterministic
138
+ % sequential maplist semantics while preserving solutions and failures.
139
+ tasklist(Goal, A) :- maplist(Goal, A).
140
+ tasklist(Goal, A, B) :- maplist(Goal, A, B).
141
+ tasklist(Goal, A, B, C) :- maplist(Goal, A, B, C).
142
+ tasklist(Goal, A, B, C, D) :- maplist(Goal, A, B, C, D).
143
+ tasklist(Goal, A, B, C, D, E) :- maplist(Goal, A, B, C, D, E).
144
+ tasklist(Goal, A, B, C, D, E, F) :- maplist(Goal, A, B, C, D, E, F).
145
+ tasklist(Goal, A, B, C, D, E, F, G) :- maplist(Goal, A, B, C, D, E, F, G).
146
+
102
147
  append([], []).
103
148
  append([Xs|Xss], Ys) :-
104
149
  append(Xs, Rest, Ys),
@@ -115,6 +160,25 @@ memberchk(X, Xs) :- member(X, Xs), !.
115
160
  select(X, [X|Xs], Xs).
116
161
  select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).
117
162
 
163
+ selectchk(X, Xs, Rest) :- select(X, Xs, Rest), !.
164
+
165
+ subtract([], _, []) :- !.
166
+ subtract([X|Xs], Ys, Rest) :- memberchk(X, Ys), !, subtract(Xs, Ys, Rest).
167
+ subtract([X|Xs], Ys, [X|Rest]) :- subtract(Xs, Ys, Rest).
168
+
169
+ union([], Ys, Ys).
170
+ union([X|Xs], Ys, Union) :- member(X, Ys), !, union(Xs, Ys, Union).
171
+ union([X|Xs], Ys, [X|Union]) :- union(Xs, Ys, Union).
172
+
173
+ intersection([], _, []).
174
+ intersection([X|Xs], Ys, [X|Intersection]) :- member(X, Ys), !, intersection(Xs, Ys, Intersection).
175
+ intersection([_|Xs], Ys, Intersection) :- intersection(Xs, Ys, Intersection).
176
+
177
+ is_set(Set) :-
178
+ sort(Set, Sorted),
179
+ length(Set, Length),
180
+ length(Sorted, Length).
181
+
118
182
  last([X], X).
119
183
  last([_|Xs], X) :- last(Xs, X).
120
184
 
package/src/lib/random.pl CHANGED
@@ -1,13 +1,13 @@
1
1
  /** Reproducible pseudo-random values.
2
2
 
3
- random/3 is EyeProlog's explicit-state interface. maybe/0,
3
+ random/3 is EyeProlog's explicit-state interface. maybe/0, maybe/1, maybe/2,
4
4
  random/1, random_integer/3, and set_random/1 are the mutable-seed library
5
5
  interface used for compatibility. random/1 uses EyeProlog's private native
6
6
  state step for hot-loop performance; random/3 remains the portable explicit-
7
7
  state Park-Miller generator, and both retain the same sequence.
8
8
  */
9
9
 
10
- :- module(random, [maybe/0, random/1, random/3, random_integer/3, set_random/1]).
10
+ :- module(random, [maybe/0, maybe/1, maybe/2, random/1, random/3, random_integer/3, set_random/1]).
11
11
 
12
12
  :- use_module(library(iso_ext), [bb_get/2, bb_put/2]).
13
13
  :- use_module(library(error), [instantiation_error/1, type_error/3]).
@@ -15,6 +15,15 @@
15
15
  maybe :-
16
16
  random_integer(0, 2, 0).
17
17
 
18
+ maybe(Probability) :-
19
+ random(Value),
20
+ Value < Probability.
21
+
22
+ maybe(K, N) :-
23
+ Probability is K / N,
24
+ random(Value),
25
+ Value < Probability.
26
+
18
27
 
19
28
  random(Value) :-
20
29
  eyeprolog__random_value(Value).
@@ -2,10 +2,10 @@
2
2
 
3
3
  EyeProlog tables predicates only when requested explicitly with
4
4
  `:- table ...`. The library keeps the portable start_tabling/2 and
5
- abolish_all_tables/0 surface used by Scryer/Trealla-compatible source.
5
+ abolish_all_tables/0 and abolish_table/1 surface used by Scryer/Trealla-compatible source.
6
6
  */
7
7
 
8
- :- module(tabling, [start_tabling/2, abolish_all_tables/0, op(1150, fx, table)]).
8
+ :- module(tabling, [start_tabling/2, abolish_all_tables/0, abolish_table/1, op(1150, fx, table)]).
9
9
 
10
10
  :- meta_predicate(start_tabling(?, 0)).
11
11
 
@@ -14,3 +14,24 @@ start_tabling(_, Worker) :-
14
14
 
15
15
  abolish_all_tables :-
16
16
  eyeprolog__abolish_all_tables.
17
+
18
+
19
+ abolish_table(Spec) :-
20
+ ( var(Spec) -> throw(error(instantiation_error, abolish_table/1))
21
+ ; tabling__abolish_table(Spec)
22
+ ).
23
+
24
+ tabling__abolish_table((A,B)) :- !,
25
+ tabling__abolish_table(A),
26
+ tabling__abolish_table(B).
27
+ tabling__abolish_table(Name//Arity) :-
28
+ atom(Name), integer(Arity), Arity >= 0, !,
29
+ ExpandedArity is Arity + 2,
30
+ tabling__abolish_table(Name/ExpandedArity).
31
+ tabling__abolish_table(Name/Arity) :-
32
+ atom(Name), integer(Arity), Arity >= 0, !,
33
+ ( eyeprolog__abolish_table(Name, Arity) -> true
34
+ ; throw(error(existence_error(table, Name/Arity), abolish_table/1))
35
+ ).
36
+ tabling__abolish_table(Spec) :-
37
+ throw(error(type_error(predicate_indicator, Spec), abolish_table/1)).
@@ -50,10 +50,13 @@ export const eyePrologLibraryAutoload = Object.freeze({
50
50
  "$-/1": "debug",
51
51
  "$/1": "debug",
52
52
  "abolish_all_tables/0": "tabling",
53
+ "abolish_table/1": "tabling",
53
54
  "add_edges/3": "ugraphs",
54
55
  "add_vertices/3": "ugraphs",
56
+ "aggregate_all/3": "aggregate",
55
57
  "aggregate_max/5": "aggregate",
56
58
  "aggregate_min/5": "aggregate",
59
+ "aggregate/3": "aggregate",
57
60
  "all_different/1": "clpz",
58
61
  "all_distinct/1": "clpz",
59
62
  "append/2": "lists",
@@ -139,6 +142,7 @@ export const eyePrologLibraryAutoload = Object.freeze({
139
142
  "edges/2": "ugraphs",
140
143
  "element/3": "clpz",
141
144
  "empty_assoc/1": "assoc",
145
+ "exclude/3": "lists",
142
146
  "expmod/4": "arithmetic",
143
147
  "fd_dom/2": "clpz",
144
148
  "fd_inf/2": "clpz",
@@ -161,6 +165,7 @@ export const eyePrologLibraryAutoload = Object.freeze({
161
165
  "format/2": "format",
162
166
  "format/3": "format",
163
167
  "freeze/2": "freeze",
168
+ "frozen/2": "freeze",
164
169
  "ge/2": "comparison",
165
170
  "gen_assoc/3": "assoc",
166
171
  "gen_int/1": "between",
@@ -181,13 +186,16 @@ export const eyePrologLibraryAutoload = Object.freeze({
181
186
  "hex_bytes/2": "crypto",
182
187
  "if_/3": "reif",
183
188
  "in/2": "clpz",
189
+ "include/3": "lists",
184
190
  "indomain/1": "clpz",
185
191
  "ins/2": "clpz",
186
192
  "instantiation_error/0": "error",
187
193
  "instantiation_error/1": "error",
188
194
  "integer_si/1": "si",
195
+ "intersection/3": "lists",
189
196
  "is_assoc/1": "assoc",
190
197
  "is_ordset/1": "ordsets",
198
+ "is_set/1": "lists",
191
199
  "join/3": "strings",
192
200
  "label/1": "clpz",
193
201
  "labeling/1": "clpb",
@@ -226,6 +234,8 @@ export const eyePrologLibraryAutoload = Object.freeze({
226
234
  "max_list/2": "lists",
227
235
  "max_sleep_time/1": "time",
228
236
  "maybe/0": "random",
237
+ "maybe/1": "random",
238
+ "maybe/2": "random",
229
239
  "member/2": "lists",
230
240
  "memberchk/2": "lists",
231
241
  "memberd_t/3": "reif",
@@ -309,12 +319,14 @@ export const eyePrologLibraryAutoload = Object.freeze({
309
319
  "representation_error/1": "error",
310
320
  "reset_gensym/1": "gensym",
311
321
  "resource_error/1": "error",
322
+ "resource_error/2": "error",
312
323
  "reverse/2": "lists",
313
324
  "same_length/2": "lists",
314
325
  "sat_count/2": "clpb",
315
326
  "sat/1": "clpb",
316
327
  "scalar_product/4": "clpz",
317
328
  "select/3": "lists",
329
+ "selectchk/3": "lists",
318
330
  "seq/3": "dcgs",
319
331
  "seqq/3": "dcgs",
320
332
  "serialized/2": "clpz",
@@ -333,11 +345,19 @@ export const eyePrologLibraryAutoload = Object.freeze({
333
345
  "statistics/2": "time",
334
346
  "string_concat/3": "strings",
335
347
  "substring/4": "strings",
348
+ "subtract/3": "lists",
336
349
  "succ/2": "iso_ext",
337
350
  "sum_list/2": "lists",
338
351
  "sum/3": "clpz",
339
352
  "sumall/3": "aggregate",
340
353
  "take/3": "lists",
354
+ "tasklist/2": "lists",
355
+ "tasklist/3": "lists",
356
+ "tasklist/4": "lists",
357
+ "tasklist/5": "lists",
358
+ "tasklist/6": "lists",
359
+ "tasklist/7": "lists",
360
+ "tasklist/8": "lists",
341
361
  "taut/2": "clpb",
342
362
  "term_attributed_variables/2": "atts",
343
363
  "term_si/1": "si",
@@ -357,6 +377,7 @@ export const eyePrologLibraryAutoload = Object.freeze({
357
377
  "type_error/2": "error",
358
378
  "type_error/3": "error",
359
379
  "ugraph_union/3": "ugraphs",
380
+ "union/3": "lists",
360
381
  "unsetenv/1": "os",
361
382
  "uppercase/2": "strings",
362
383
  "uuid_string/2": "uuid",
@@ -121,8 +121,8 @@ export const eyePrologNativeLibraryIndicators = Object.freeze([
121
121
  'random/1',
122
122
  ]);
123
123
  export const eyePrologPortableLibraryIndicators = Object.freeze([
124
- 'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
125
- 'freeze/2',
124
+ 'sumall/3', 'aggregate_min/5', 'aggregate_max/5', 'aggregate_all/3', 'aggregate/3',
125
+ 'freeze/2', 'frozen/2',
126
126
  'expmod/4', 'lcm/3', 'lsb/2', 'msb/2', 'popcount/2',
127
127
  'empty_assoc/1', 'assoc_to_list/2', 'get_assoc/3', 'put_assoc/4',
128
128
  'assoc_to_keys/2', 'assoc_to_values/2', 'del_assoc/4', 'del_max_assoc/4',
@@ -141,7 +141,7 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
141
141
  '*/1', '$/1', '$-/1',
142
142
  'must_be/2', 'can_be/2', 'instantiation_error/0', 'instantiation_error/1',
143
143
  'domain_error/2', 'domain_error/3', 'type_error/2', 'type_error/3',
144
- 'representation_error/1', 'resource_error/1', 'call_with_error_context/2',
144
+ 'representation_error/1', 'resource_error/1', 'resource_error/2', 'call_with_error_context/2',
145
145
  'format_/4', 'format/2', 'format/3', 'portray_clause_/3',
146
146
  'portray_clause/1', 'portray_clause/2', 'listing/1',
147
147
  'gensym/2', 'reset_gensym/1',
@@ -150,10 +150,11 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
150
150
  '^/3', '^/4', '^/5', '^/6', '^/7', '^/8', '^/9', '^/10',
151
151
  '\\/1', '\\/2', '\\/3', '\\/4', '\\/5', '\\/6', '\\/7', '\\/8',
152
152
  '+\\/2', '+\\/3', '+\\/4', '+\\/5', '+\\/6', '+\\/7', '+\\/8', '+\\/9',
153
- 'member/2', 'memberchk/2', 'select/3', 'append/2', 'append/3', 'last/2', 'same_length/2',
153
+ 'member/2', 'memberchk/2', 'select/3', 'selectchk/3', 'subtract/3', 'union/3', 'intersection/3', 'is_set/1', 'append/2', 'append/3', 'last/2', 'same_length/2',
154
154
  'nth0/3', 'nth0/4', 'nth1/3', 'nth1/4', 'set_nth0/4', 'take/3', 'drop/3', 'slice/4', 'reverse/2',
155
- 'length/2', 'maplist/2', 'maplist/3', 'maplist/4', 'maplist/5',
156
- 'maplist/6', 'maplist/7', 'maplist/8', 'maplist/9', 'foldl/4', 'foldl/5', 'foldl/6',
155
+ 'length/2', 'exclude/3', 'include/3', 'maplist/2', 'maplist/3', 'maplist/4', 'maplist/5',
156
+ 'maplist/6', 'maplist/7', 'maplist/8', 'maplist/9',
157
+ 'tasklist/2', 'tasklist/3', 'tasklist/4', 'tasklist/5', 'tasklist/6', 'tasklist/7', 'tasklist/8', 'foldl/4', 'foldl/5', 'foldl/6',
157
158
  'sum_list/2', 'min_list/2', 'max_list/2', 'list_to_set/2',
158
159
  'transpose/2', 'list_max/2', 'list_min/2', 'permutation/2',
159
160
  'is_ordset/1', 'list_to_ord_set/2', 'ord_add_element/3', 'ord_del_element/3',
@@ -166,7 +167,7 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
166
167
  'phrase_from_file/2', 'phrase_from_file/3', 'phrase_from_stream/2', 'phrase_to_file/2',
167
168
  'phrase_to_file/3', 'phrase_to_stream/2',
168
169
  'smallest_divisor_from/3',
169
- 'maybe/0', 'random/3', 'random_integer/3', 'set_random/1',
170
+ 'maybe/0', 'maybe/1', 'maybe/2', 'random/3', 'random_integer/3', 'set_random/1',
170
171
  ',/3', ';/3', '=/3', 'cond_t/3', 'dif/3', 'if_/3', 'memberd_t/3',
171
172
  'tfilter/3', 'tmember/2', 'tmember_t/3', 'tpartition/4',
172
173
  'atom_si/1', 'integer_si/1', 'atomic_si/1', 'list_si/1', 'character_si/1',
@@ -175,7 +176,7 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
175
176
  'number_string/2', 'atom_string/2', 'term_string/2', 'string_concat/3',
176
177
  'contains/2', 'matches/2', 'join/3', 'substring/4',
177
178
  'numbervars/3', 'copy_term_nat/2',
178
- 'start_tabling/2', 'abolish_all_tables/0',
179
+ 'start_tabling/2', 'abolish_all_tables/0', 'abolish_table/1',
179
180
  'max_sleep_time/1', 'current_time/1', 'format_time/4',
180
181
  'add_edges/3', 'add_vertices/3', 'complement/2', 'compose/3', 'connect_ugraph/3',
181
182
  'del_edges/3', 'del_vertices/3', 'edges/2', 'neighbors/3', 'neighbours/3',
@@ -1,4 +1,6 @@
1
- // Runtime table-cache lifecycle adapter for library(tabling).
1
+ // Runtime table-cache lifecycle adapters for library(tabling).
2
+
3
+ import { ATOM, NUMBER, deref } from './term.js';
2
4
 
3
5
  function* abolishAllTablesBuiltin({ solver, env }) {
4
6
  solver.memo.clear();
@@ -15,8 +17,43 @@ function* abolishAllTablesBuiltin({ solver, env }) {
15
17
  yield env;
16
18
  }
17
19
 
20
+ function clearPredicateFromMemo(memo, prefix) {
21
+ for (const key of [...memo.keys()]) {
22
+ if (key.startsWith(prefix)) memo.delete(key);
23
+ }
24
+ }
25
+
26
+ function clearPredicateTables(solver, module, name, arity) {
27
+ const broadKey = `${module}:${name}/${arity}`;
28
+ clearPredicateFromMemo(solver.memo, `${broadKey}:`);
29
+ solver.subsumptiveMemo.delete(broadKey);
30
+ for (const scope of solver.innerTableScopes.values()) {
31
+ clearPredicateFromMemo(scope.memo, `${broadKey}:`);
32
+ scope.subsumptiveMemo.delete(broadKey);
33
+ }
34
+ }
35
+
36
+ function* abolishTableBuiltin({ solver, goal, env }) {
37
+ const name = deref(goal.args[0], env);
38
+ const arity = deref(goal.args[1], env);
39
+ if (name.type !== ATOM || arity.type !== NUMBER || !/^\d+$/.test(arity.name)) return;
40
+ const arityValue = Number(arity.name);
41
+ const matches = [...solver.program.groups.values()].filter((group) =>
42
+ group.name === name.name && group.arity === arityValue && group.tabled === true);
43
+ if (matches.length === 0) return;
44
+ for (const group of matches) clearPredicateTables(solver, group.module, group.name, group.arity);
45
+ // A completed WFS/Datalog model can depend on a tabled predicate; these
46
+ // caches do not expose per-predicate dependency keys, so invalidate them
47
+ // conservatively while preserving unrelated explicit memo tables.
48
+ solver.wfsModels.clear();
49
+ solver.datalogModels.clear();
50
+ solver.tableCoordinator = null;
51
+ yield env;
52
+ }
53
+
18
54
  export const tablingHostBuiltins = {
19
55
  register(registry) {
20
56
  registry.add('eyeprolog__abolish_all_tables', 0, abolishAllTablesBuiltin, { deterministic: true, eyePrologLibrary: true });
57
+ registry.add('eyeprolog__abolish_table', 2, abolishTableBuiltin, { deterministic: true, eyePrologLibrary: true });
21
58
  },
22
59
  };
@@ -57,6 +57,23 @@ export function runArchitecture(reporter = new TestReporter()) {
57
57
  }
58
58
  if (issues.length > 0) throw new Error(issues.join('\n'));
59
59
  });
60
+ reporter.test('overlapping bundled libraries cover the pinned Trealla export surface', () => {
61
+ const snapshotPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'trealla-library-exports.json');
62
+ const expected = JSON.parse(fs.readFileSync(snapshotPath, 'utf8'));
63
+ const issues = [];
64
+ for (const [module, indicators] of Object.entries(expected)) {
65
+ const file = path.join(ROOT, 'lib', `${module}.pl`);
66
+ if (!fs.existsSync(file)) {
67
+ issues.push(`missing src/lib/${module}.pl`);
68
+ continue;
69
+ }
70
+ const actual = new Set(moduleExportIndicators(fs.readFileSync(file, 'utf8'), `src/lib/${module}.pl`));
71
+ for (const indicator of indicators) {
72
+ if (!actual.has(indicator)) issues.push(`${module}: missing Trealla export ${indicator}`);
73
+ }
74
+ }
75
+ if (issues.length > 0) throw new Error(issues.join('\n'));
76
+ });
60
77
  reporter.test('legacy grab-bag library host files are absent', () => {
61
78
  for (const name of ['library-host.js', 'scryer-compat.js']) {
62
79
  if (fs.existsSync(path.join(ROOT, name))) throw new Error(`${name} must stay split into module-owned hosts`);
@@ -6493,7 +6493,7 @@ answer(ok) :-
6493
6493
  assertEqual(Boolean(registry.get('is', 2)), true, 'ISO is/2 exists');
6494
6494
  assertEqual(Boolean(registry.get('append', 3)), false, 'append/3 is not ISO core');
6495
6495
  assertEqual(library.eyePrologLibrary, true, 'complete registry marker');
6496
- assertEqual(library.defs.size, 215, 'EyeProlog registry contains ISO definitions, cleanup controls, observability extensions, WFS tnot/1, and generic library adapters');
6496
+ assertEqual(library.defs.size, 216, 'EyeProlog registry contains ISO definitions, cleanup controls, observability extensions, WFS tnot/1, and generic library adapters');
6497
6497
  assertEqual(registry.get('eyeprolog__dynify', 1), null, 'Eyelet dynify adapter is absent from the ISO registry');
6498
6498
  assertEqual(Boolean(library.get('eyeprolog__dynify', 1)), true, 'Eyelet dynify adapter is an internal EyeProlog library primitive');
6499
6499
  assertEqual(registry.get('eyeprolog__eyelet_emit', 2), null, 'Eyelet event adapter is absent from the ISO registry');
@@ -6517,7 +6517,7 @@ answer(ok) :-
6517
6517
  assertEqual(registry.get('setup_call_cleanup', 3), null, 'setup_call_cleanup/3 is absent from the ISO registry');
6518
6518
  assertEqual(Boolean(library.get('setup_call_cleanup', 3)), true, 'setup_call_cleanup/3 is an EyeProlog cleanup control');
6519
6519
  assertEqual(registeredNativeEyePrologLibraryNames().length, 109, 'public host-supported EyeProlog library count');
6520
- assertEqual(eyePrologPortableLibraryIndicators.length, 259, 'portable Prolog library count');
6520
+ assertEqual(eyePrologPortableLibraryIndicators.length, 280, 'portable Prolog library count');
6521
6521
  assertEqual(eyePrologInteropLibraryIndicators.length, 218, 'cross-implementation interop profile count');
6522
6522
  assertEqual(eyePrologInteropLibraryModules.length, 26, 'common explicit library module profile count');
6523
6523
  assertEqual(eyePrologInteropAutoload['member/2'], 'lists', 'member/2 canonical autoload');
@@ -6535,7 +6535,7 @@ answer(ok) :-
6535
6535
  assertEqual(eyePrologNativeLibraryIndicators.length, 109, 'host-supported library count');
6536
6536
  assertEqual(eyePrologNativeLibraryIndicators.includes('call_nth/2'), true, 'call_nth/2 remains classified as host-supported');
6537
6537
  assertEqual(eyePrologNativeLibraryIndicators.includes('random/1'), true, 'stateful random/1 is classified as host-supported');
6538
- assertEqual(eyePrologLibraryIndicators.length, 368, 'complete non-ISO EyeProlog library surface');
6538
+ assertEqual(eyePrologLibraryIndicators.length, 389, 'complete non-ISO EyeProlog library surface');
6539
6539
  assertEqual(registry.get('eyeprolog__call_nth', 2), null, 'private call_nth adapter is absent from ISO registry');
6540
6540
  assertEqual(Boolean(library.get('eyeprolog__call_nth', 2)), true, 'private call_nth adapter is registered for EyeProlog');
6541
6541
  assertEqual(Boolean(library.get('eyeprolog__call_residue_vars', 2)), true, 'private call_residue_vars adapter is registered for EyeProlog');
@@ -6588,6 +6588,51 @@ answer(ok) :-
6588
6588
  assertEqual(program.findGroup('random', 3)?.module, 'random', 'random/3 is imported from library(random)');
6589
6589
  },
6590
6590
  },
6591
+ {
6592
+ name: 'Trealla library overlap predicates execute with EyeProlog semantics',
6593
+ run: () => {
6594
+ const program = Program.parse(`
6595
+ :- use_module(library(aggregate)).
6596
+ :- use_module(library(error)).
6597
+ :- use_module(library(freeze)).
6598
+ :- use_module(library(lists)).
6599
+ :- use_module(library(random)).
6600
+ :- use_module(library(tabling)).
6601
+
6602
+ positive(X) :- X > 0.
6603
+ inc(X, Y) :- Y is X + 1.
6604
+
6605
+ :- dynamic(edge/2).
6606
+ :- table(path/2).
6607
+ path(X, Y) :- edge(X, Y).
6608
+ path(X, Z) :- edge(X, Y), path(Y, Z).
6609
+
6610
+ trealla_overlap_probe :-
6611
+ aggregate_all(count, member(_, [a,b,c]), 3),
6612
+ aggregate_all(sum(X), member(X, [1,2,3]), 6),
6613
+ aggregate_all(bag(X), member(X, [a,b]), [a,b]),
6614
+ aggregate_all(set(X), member(X, [b,a,b]), [a,b]),
6615
+ aggregate(sum(X), member(K-X, [a-1,a-2,b-3]), 3), K = a,
6616
+ aggregate(sum(Y), J^member(J-Y, [a-1,a-2,b-3]), 6),
6617
+ selectchk(b, [a,b,c], [a,c]),
6618
+ subtract([a,b,a,c], [a], [b,c]),
6619
+ union([a,b], [b,c], [a,b,c]),
6620
+ intersection([a,b,c], [b,d,c], [b,c]),
6621
+ is_set([a,b,c]), \\+ is_set([a,a]),
6622
+ include(positive, [-1,2,0,3], [2,3]),
6623
+ exclude(positive, [-1,2,0,3], [-1,0]),
6624
+ tasklist(inc, [1,2,3], [2,3,4]),
6625
+ maybe(1.0), maybe(1, 1),
6626
+ freeze(F, true), frozen(F, Frozen), Frozen \\== true, F = ready,
6627
+ catch(resource_error(memory, context), error(resource_error(memory), context), true),
6628
+ assertz(edge(a,b)), path(a,b),
6629
+ retract(edge(a,b)), assertz(edge(a,c)),
6630
+ abolish_table(path/2), \\+ path(a,b), path(a,c),
6631
+ catch(abolish_table(missing/1), error(existence_error(table, missing/1), abolish_table/1), true).
6632
+ `);
6633
+ assertEqual(run(program, { goal: 'trealla_overlap_probe' }).stdout, 'trealla_overlap_probe.\n', 'Trealla overlap execution');
6634
+ },
6635
+ },
6591
6636
  {
6592
6637
  name: 'Prologue facade re-exports canonical library predicates without conflicts',
6593
6638
  run: () => {
@@ -0,0 +1,28 @@
1
+ {
2
+ "aggregate": ["aggregate_all/3", "aggregate/3"],
3
+ "arithmetic": ["lsb/2", "msb/2", "popcount/2", "number_to_rational/2", "rational_numerator_denominator/3"],
4
+ "assoc": ["empty_assoc/1", "is_assoc/1", "assoc_to_list/2", "assoc_to_keys/2", "assoc_to_values/2", "gen_assoc/3", "get_assoc/3", "get_assoc/5", "list_to_assoc/2", "map_assoc/2", "map_assoc/3", "max_assoc/3", "min_assoc/3", "ord_list_to_assoc/2", "put_assoc/4", "del_assoc/4", "del_min_assoc/4", "del_max_assoc/4"],
5
+ "atts": ["get_attr/3", "put_attr/3", "del_attr/2"],
6
+ "charsio": ["char_type/2", "get_line_to_chars/3", "get_single_char/1", "get_n_chars/3"],
7
+ "clpb": ["sat/1", "taut/2", "labeling/1", "sat_count/2", "weighted_maximum/3", "random_labeling/2"],
8
+ "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"],
9
+ "debug": ["*/1", "$/1", "$-/1"],
10
+ "dif": ["dif/2"],
11
+ "error": ["must_be/2", "can_be/2", "instantiation_error/0", "domain_error/2", "type_error/2", "representation_error/1", "resource_error/1", "resource_error/2", "instantiation_error/1", "domain_error/3", "type_error/3", "call_with_error_context/2"],
12
+ "format": ["format_/4", "format/2", "format/3", "portray_clause_/3", "portray_clause/1", "portray_clause/2", "listing/1"],
13
+ "freeze": ["freeze/2", "frozen/2"],
14
+ "gensym": ["gensym/2", "reset_gensym/1"],
15
+ "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"],
16
+ "lists": ["member/2", "memberchk/2", "select/3", "selectchk/3", "append/2", "append/3", "subtract/3", "union/3", "intersection/3", "is_set/1", "nth1/3", "nth0/3", "nth1/4", "nth0/4", "last/2", "same_length/2", "transpose/2", "sum_list/2", "max_list/2", "min_list/2", "list_to_set/2", "reverse/2", "exclude/3", "include/3", "permutation/2", "foldl/4", "foldl/5", "foldl/6", "maplist/2", "maplist/3", "maplist/4", "maplist/5", "maplist/6", "maplist/7", "maplist/8", "tasklist/2", "tasklist/3", "tasklist/4", "tasklist/5", "tasklist/6", "tasklist/7", "tasklist/8"],
17
+ "ordsets": ["is_ordset/1", "list_to_ord_set/2", "ord_add_element/3", "ord_del_element/3", "ord_selectchk/3", "ord_intersect/2", "ord_intersect/3", "ord_intersection/3", "ord_intersection/4", "ord_disjoint/2", "ord_subtract/3", "ord_union/2", "ord_union/3", "ord_union/4", "ord_subset/2", "ord_empty/1", "ord_memberchk/2", "ord_symdiff/3", "ord_seteq/2", "ord_intersection/2"],
18
+ "pairs": ["pairs_keys_values/3", "pairs_keys/2", "pairs_values/2", "group_pairs_by_key/2", "map_list_to_pairs/3"],
19
+ "pio": ["phrase_from_file/2", "phrase_from_file/3", "phrase_to_file/2", "phrase_to_file/3", "phrase_to_stream/2"],
20
+ "random": ["maybe/0", "maybe/1", "maybe/2", "random_integer/3", "set_random/1"],
21
+ "reif": ["if_/3", "=/3", ",/3", ";/3", "cond_t/3", "dif/3", "memberd_t/3", "tfilter/3", "tmember/2", "tmember_t/3", "tpartition/4"],
22
+ "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"],
23
+ "tabling": ["start_tabling/2", "abolish_all_tables/0", "abolish_table/1"],
24
+ "time": ["current_time/1", "format_time/4"],
25
+ "ugraphs": ["add_edges/3", "add_vertices/3", "complement/2", "compose/3", "del_edges/3", "del_vertices/3", "edges/2", "neighbors/3", "neighbours/3", "reachable/3", "top_sort/2", "top_sort/3", "transitive_closure/2", "transpose_ugraph/2", "vertices/2", "vertices_edges_to_ugraph/3", "ugraph_union/3", "connect_ugraph/3"],
26
+ "uuid": ["uuidv4/1", "uuidv4_string/1", "uuid_string/2"],
27
+ "when": ["when/2"]
28
+ }
@@ -6308,12 +6308,12 @@ so side effects occur in Prolog execution order.
6308
6308
 
6309
6309
  ### The EyeProlog library
6310
6310
 
6311
- EyeProlog exposes **368 distinct non-ISO library and normal-extension predicate
6311
+ EyeProlog exposes **389 distinct non-ISO library and normal-extension predicate
6312
6312
  indicators** in addition to the 129 indicators in its isolated ISO profile.
6313
- **259 are defined entirely as ordinary Prolog clauses** in focused modules under
6313
+ **280 are defined entirely as ordinary Prolog clauses** in focused modules under
6314
6314
  `src/lib/`; **109 use host support** for control, attributed variables,
6315
6315
  constraints, character conversion, filesystem/OS access, timing, cryptography,
6316
- or observability. The ISO and library catalogs therefore cover **497 distinct predicate indicators**. A normal-runtime predicate that is intentionally
6316
+ or observability. The ISO and library catalogs therefore cover **518 distinct predicate indicators**. A normal-runtime predicate that is intentionally
6317
6317
  re-exported by a compatibility module is counted once in this library surface:
6318
6318
  for example `call_cleanup/2` and `setup_call_cleanup/3` are exported by
6319
6319
  `library(iso_ext)`, while `time/1` and `statistics/2` are available from
@@ -6392,7 +6392,7 @@ bindings make one aligned subterm pair sufficient. For example:
6392
6392
 
6393
6393
  | Module | Exported predicate indicators | Primary role |
6394
6394
  | --- | --- | --- |
6395
- | `library(aggregate)` | `sumall/3`, `aggregate_min/5`, `aggregate_max/5` | Aggregation |
6395
+ | `library(aggregate)` | `sumall/3`, `aggregate_min/5`, `aggregate_max/5`, `aggregate_all/3`, `aggregate/3` | Aggregation, including Trealla-compatible aggregate templates |
6396
6396
  | `library(arithmetic)` | `expmod/4`, `lcm/3`, `lsb/2`, `msb/2`, `number_to_rational/2`, `number_to_rational/3`, `popcount/2`, `rational_numerator_denominator/3` | Scryer-compatible arithmetic helpers and rational-form conversion |
6397
6397
  | `library(assoc)` | `empty_assoc/1`, `assoc_to_keys/2`, `assoc_to_list/2`, `assoc_to_values/2`, `del_assoc/4`, `del_max_assoc/4`, `del_min_assoc/4`, `gen_assoc/3`, `get_assoc/3`, `get_assoc/5`, `is_assoc/1`, `list_to_assoc/2`, `map_assoc/2`, `map_assoc/3`, `max_assoc/3`, `min_assoc/3`, `ord_list_to_assoc/2`, `put_assoc/4` | AVL association trees; reused from the shared portable source |
6398
6398
  | `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 |
@@ -6406,26 +6406,26 @@ bindings make one aligned subterm pair sufficient. For example:
6406
6406
  | `library(dcgs)` | `-->/2`, `.../2`, `phrase/2`, `phrase/3`, `phrase/4`, `phrase/5`, `seq/3`, `seqq/3` | Full Scryer DCG export surface; nonterminals are shown at their expanded arities |
6407
6407
  | `library(debug)` | `*/1`, `$/1`, `$-/1`, `debug/1`, `debug/3`, `nodebug/1`, `bb_get/2`, `bb_put/2`, `bb_b_put/2` | Declarative debug operators plus compatibility re-exports of the canonical `iso_ext` blackboard |
6408
6408
  | `library(dif)` | `dif/2` | Common module facade over native delayed disequality |
6409
- | `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 |
6409
+ | `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`, `resource_error/2`, `call_with_error_context/2` | Error checking and construction |
6410
6410
  | `library(eyelet)` | `stable/1`, `becomes/2` | Eyelet forward-reasoning driver and state helpers; the `:+` operator is exported by the module and its fixed point is implemented in Prolog |
6411
6411
  | `library(files)` | `delete_directory/1`, `delete_file/1`, `directory_exists/1`, `directory_files/2`, `file_access_time/2`, `file_copy/2`, `file_creation_time/2`, `file_exists/1`, `file_modification_time/2`, `file_size/2`, `make_directory/1`, `make_directory_path/1`, `path_canonical/2`, `path_segments/2`, `rename_file/2`, `working_directory/2` | Full Scryer filesystem surface backed by the Node host where filesystem access is required |
6412
6412
  | `library(format)` | `format_/4`, `format/2`, `format/3`, `listing/1`, `portray_clause_/3`, `portray_clause/1`, `portray_clause/2` | Formatted DCG text and output; `format_/4` and `portray_clause_/3` are the expanded nonterminals |
6413
- | `library(freeze)` | `freeze/2` | Delayed goals |
6413
+ | `library(freeze)` | `freeze/2`, `frozen/2` | Delayed goals and residual suspension inspection |
6414
6414
  | `library(gensym)` | `gensym/2`, `reset_gensym/1` | Process-local generated atoms |
6415
6415
  | `library(iso_ext)` | `bb_b_put/2`, `bb_get/2`, `bb_put/2`, `call_cleanup/2`, `call_nth/2`, `call_residue_vars/2`, `call_with_inference_limit/3`, `cfor/3`, `copy_term/3`, `copy_term_nat/2`, `countall/2`, `findall/4`, `forall/2`, `partial_string/1`, `partial_string/3`, `partial_string_tail/2`, `setup_call_cleanup/3`, `succ/2`, `time/1`, `variant/2` | Scryer ISO extensions plus EyeProlog compatibility helpers |
6416
6416
  | `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 |
6417
- | `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`, `maplist/9`, `foldl/4`, `foldl/5`, `foldl/6`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `list_max/2`, `list_min/2`, `permutation/2`, `transpose/2`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4` | List relations and shared matrix/permutation helpers |
6417
+ | `library(lists)` | `member/2`, `memberchk/2`, `select/3`, `selectchk/3`, `subtract/3`, `union/3`, `intersection/3`, `is_set/1`, `append/2`, `append/3`, `last/2`, `same_length/2`, `nth0/3`, `nth0/4`, `nth1/3`, `nth1/4`, `reverse/2`, `length/2`, `include/3`, `exclude/3`, `maplist/2`, `maplist/3`, `maplist/4`, `maplist/5`, `maplist/6`, `maplist/7`, `maplist/8`, `maplist/9`, `tasklist/2`, `tasklist/3`, `tasklist/4`, `tasklist/5`, `tasklist/6`, `tasklist/7`, `tasklist/8`, `foldl/4`, `foldl/5`, `foldl/6`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `list_max/2`, `list_min/2`, `permutation/2`, `transpose/2`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4` | List relations and shared matrix/permutation helpers; `tasklist/*` is a sequential compatibility fallback |
6418
6418
  | `library(ordsets)` | `is_ordset/1`, `list_to_ord_set/2`, `ord_add_element/3`, `ord_del_element/3`, `ord_disjoint/2`, `ord_empty/1`, `ord_intersect/2`, `ord_intersect/3`, `ord_intersection/2`, `ord_intersection/3`, `ord_intersection/4`, `ord_memberchk/2`, `ord_selectchk/3`, `ord_seteq/2`, `ord_subset/2`, `ord_subtract/3`, `ord_symdiff/3`, `ord_union/2`, `ord_union/3`, `ord_union/4` | Ordered-set relations; reused upstream source |
6419
6419
  | `library(os)` | `argv/1`, `getenv/2`, `pid/1`, `raw_argv/1`, `setenv/2`, `shell/1`, `shell/2`, `unsetenv/1` | Environment, shell, PID, and command-line access backed by the Node host |
6420
6420
  | `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 |
6421
6421
  | `library(pio)` | `phrase_from_file/2`, `phrase_from_file/3`, `phrase_from_stream/2`, `phrase_to_file/2`, `phrase_to_file/3`, `phrase_to_stream/2` | Scryer-compatible eager DCG file/stream I/O with character-list and atom paths |
6422
6422
  | `library(primes)` | `smallest_divisor_from/3` | Prime factor support |
6423
6423
  | `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 |
6424
- | `library(random)` | `maybe/0`, `random/1`, `random/3`, `random_integer/3`, `set_random/1` | Common mutable-seed interface plus EyeProlog's pure state-threaded generator |
6424
+ | `library(random)` | `maybe/0`, `maybe/1`, `maybe/2`, `random/1`, `random/3`, `random_integer/3`, `set_random/1` | Trealla-compatible probability helpers plus the common mutable-seed interface and EyeProlog's pure state-threaded generator |
6425
6425
  | `library(reif)` | `,/3`, `;/3`, `=/3`, `cond_t/3`, `dif/3`, `if_/3`, `memberd_t/3`, `tfilter/3`, `tmember/2`, `tmember_t/3`, `tpartition/4` | Reified conditions and list filtering; reused upstream source |
6426
6426
  | `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) |
6427
6427
  | `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 |
6428
- | `library(tabling)` | `abolish_all_tables/0`, `start_tabling/2` | Common helpers for explicitly declared tabling |
6428
+ | `library(tabling)` | `abolish_all_tables/0`, `abolish_table/1`, `start_tabling/2` | Common helpers for explicitly declared tabling, including targeted invalidation |
6429
6429
  | `library(terms)` | `numbervars/3`, `copy_term_nat/2` | Term operations used by bundled libraries |
6430
6430
  | `library(time)` | `current_time/1`, `format_time/4`, `max_sleep_time/1`, `sleep/1`, `statistics/2`, `time/1` | Clock timestamps, sleep limits, timing/statistics, and the expanded `format_time//2` nonterminal |
6431
6431
  | `library(ugraphs)` | `add_edges/3`, `add_vertices/3`, `complement/2`, `compose/3`, `connect_ugraph/3`, `del_edges/3`, `del_vertices/3`, `edges/2`, `neighbors/3`, `neighbours/3`, `reachable/3`, `top_sort/2`, `top_sort/3`, `transitive_closure/2`, `transpose_ugraph/2`, `ugraph_union/3`, `vertices/2`, `vertices_edges_to_ugraph/3` | Directed graph relations; reused upstream source |
@@ -6462,7 +6462,13 @@ narrower than either implementation's union of exports; EyeProlog's explicit-sta
6462
6462
  interfaces. Separately, all 32 bundled EyeProlog modules whose basenames overlap
6463
6463
  Scryer's current `src/lib/` tree are checked against the frozen export snapshot in
6464
6464
  `test/scryer-library-exports.json` and cover the corresponding Scryer public
6465
- predicate surface.
6465
+ predicate surface. The same structural check is now applied to Trealla: the 26
6466
+ bundled modules that have public-module counterparts in Trealla `library/` cover
6467
+ Trealla's exported predicates at pinned upstream commit
6468
+ `f7a93bd521c07a4841f5123348111dd005918c89`, recorded in
6469
+ `test/trealla-library-exports.json`. This is module-overlap coverage, not a claim
6470
+ that EyeProlog bundles Trealla's native host libraries such as `curl`, `gsl`,
6471
+ `janus`, `raylib`, `socket`, or `sqlite3`.
6466
6472
 
6467
6473
  Source reuse is preferred over translation. `clpb.pl`, `ordsets.pl`,
6468
6474
  `reif.pl`, and `ugraphs.pl` retain the upstream Prolog algorithms and license
@@ -6476,7 +6482,12 @@ compatibility. `files.pl` covers Scryer's complete filesystem export surface,
6476
6482
  while `os.pl` covers its environment/shell process-context surface. Their actual
6477
6483
  filesystem and OS side effects are isolated in module-owned Node adapters.
6478
6484
  `crypto.pl` exposes Scryer's complete public crypto surface; its strict Trealla/Scryer overlap is `hex_bytes/2`,
6479
- `crypto_n_random_bytes/2`, and `crypto_data_hash/3`. The
6485
+ `crypto_n_random_bytes/2`, and `crypto_data_hash/3`. Trealla-specific overlap additions include `aggregate_all/3` and
6486
+ `aggregate/3`, `frozen/2`, the set/filter/list helpers and `tasklist/2-8`,
6487
+ `maybe/1-2`, `resource_error/2`, and `abolish_table/1`. Because EyeProlog has no
6488
+ Trealla task scheduler, `tasklist/2-8` deliberately executes sequentially with
6489
+ `maplist`-equivalent success/failure semantics; it does not promise Trealla's
6490
+ parallel scheduling behavior. The
6480
6491
  [portable library overlap example](https://github.com/eyereasoner/eyeprolog/blob/main/examples/portable-library-overlap.pl)
6481
6492
  composes Boolean constraints, ordered sets, graphs, reification, delayed goals,
6482
6493
  generated names, character conversion, transposition, and explicit table