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 +1 -1
- package/package.json +1 -1
- package/src/lib/aggregate.pl +78 -1
- package/src/lib/error.pl +2 -0
- package/src/lib/freeze.pl +20 -2
- package/src/lib/lists.pl +64 -0
- package/src/lib/random.pl +11 -2
- package/src/lib/tabling.pl +23 -2
- package/src/library-autoload-index.js +21 -0
- package/src/standard-library.js +9 -8
- package/src/tabling-host.js +38 -1
- package/test/run-architecture.mjs +17 -0
- package/test/run-regression.mjs +48 -3
- package/test/trealla-library-exports.json +28 -0
- package/the-art-of-eyeprolog.md +22 -11
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
|
|
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
package/src/lib/aggregate.pl
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
/** Portable solution aggregation relations. */
|
|
2
2
|
|
|
3
|
-
|
|
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
|
|
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).
|
package/src/lib/tabling.pl
CHANGED
|
@@ -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",
|
package/src/standard-library.js
CHANGED
|
@@ -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',
|
|
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',
|
package/src/tabling-host.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
// Runtime table-cache lifecycle
|
|
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`);
|
package/test/run-regression.mjs
CHANGED
|
@@ -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,
|
|
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,
|
|
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,
|
|
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
|
+
}
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6308,12 +6308,12 @@ so side effects occur in Prolog execution order.
|
|
|
6308
6308
|
|
|
6309
6309
|
### The EyeProlog library
|
|
6310
6310
|
|
|
6311
|
-
EyeProlog exposes **
|
|
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
|
-
**
|
|
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 **
|
|
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` |
|
|
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`.
|
|
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
|