eyeprolog 1.3.0 → 1.3.1
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 +8 -5
- package/package.json +1 -1
- package/src/lib/lists.pl +30 -6
- package/src/standard-library.js +4 -0
- package/test/run-regression.mjs +17 -1
- package/the-art-of-eyeprolog.md +12 -8
package/README.md
CHANGED
|
@@ -138,14 +138,17 @@ predicates use ISO atoms or character lists. The old catch-all
|
|
|
138
138
|
EyeProlog keeps a conservative source-level interoperability profile separate
|
|
139
139
|
from the larger EyeProlog library surface. `library(lists)` follows the common
|
|
140
140
|
Trealla/Scryer organization for predicates such as `member/2`, `memberchk/2`,
|
|
141
|
-
`append/2-3`, `nth0/3-4`, `nth1/3-4`, `maplist/2-8`, and
|
|
141
|
+
`append/2-3`, `nth0/3-4`, `nth1/3-4`, `length/2`, `maplist/2-8`, and
|
|
142
|
+
`foldl/4-6`. Its `length/2` remains relational: with both arguments variable,
|
|
143
|
+
`length(Xs, N)` enumerates lists of increasing length together with `N = 0, 1,
|
|
144
|
+
2, ...`.
|
|
142
145
|
|
|
143
146
|
Outside `--iso-strict`, an otherwise undefined unqualified call may autoload a
|
|
144
147
|
predicate only when the interop profile has one canonical EyeProlog provider.
|
|
145
|
-
For example, `member/2` autoloads from `library(lists)
|
|
146
|
-
EyeProlog's internal Prologue implementation without
|
|
147
|
-
to name `library(prologue)`. Use `--no-autoload` to
|
|
148
|
-
Strict ISO mode never autoloads library predicates.
|
|
148
|
+
For example, `member/2` autoloads from `library(lists)`, while `between/3` and
|
|
149
|
+
`call_nth/2` can use EyeProlog's internal Prologue implementation without
|
|
150
|
+
requiring portable source to name `library(prologue)`. Use `--no-autoload` to
|
|
151
|
+
disable this convenience. Strict ISO mode never autoloads library predicates.
|
|
149
152
|
|
|
150
153
|
Use `-w` / `--warnings` to diagnose dependencies outside the interop profile,
|
|
151
154
|
or `--portable` to make such diagnostics fail the run. This catches both
|
package/package.json
CHANGED
package/src/lib/lists.pl
CHANGED
|
@@ -133,8 +133,17 @@ nth1(N, List, Elem, Rest) :-
|
|
|
133
133
|
|
|
134
134
|
reverse(List, Reversed) :- lists__reverse(List, [], Reversed).
|
|
135
135
|
|
|
136
|
-
|
|
137
|
-
length(List, Length)
|
|
136
|
+
% Keep the common lists:length/2 relation fully relational. In particular,
|
|
137
|
+
% length(List, Length) with both arguments variable enumerates lists of
|
|
138
|
+
% increasing length, as required by portable generators such as the issue #28
|
|
139
|
+
% number_chars/2 stress test.
|
|
140
|
+
length(List, Length) :-
|
|
141
|
+
nonvar(Length), !,
|
|
142
|
+
lists__integer(Length),
|
|
143
|
+
lists__not_less_than_zero(Length),
|
|
144
|
+
lists__length_fixed(Length, List).
|
|
145
|
+
length(List, Length) :-
|
|
146
|
+
lists__length_generate(List, 0, Length).
|
|
138
147
|
|
|
139
148
|
foldl(_, [], Acc, Acc).
|
|
140
149
|
foldl(Closure, [A|As], Acc0, Acc) :-
|
|
@@ -186,10 +195,25 @@ slice(Start, Count, List, Slice) :-
|
|
|
186
195
|
lists__reverse([], Acc, Acc).
|
|
187
196
|
lists__reverse([X|Xs], Acc, Out) :- lists__reverse(Xs, [X|Acc], Out).
|
|
188
197
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
198
|
+
lists__length_fixed(0, []).
|
|
199
|
+
lists__length_fixed(N, [_|Xs]) :-
|
|
200
|
+
N > 0,
|
|
201
|
+
N1 is N - 1,
|
|
202
|
+
lists__length_fixed(N1, Xs).
|
|
203
|
+
|
|
204
|
+
lists__length_generate([], N, N).
|
|
205
|
+
lists__length_generate([_|Xs], N0, N) :-
|
|
206
|
+
N1 is N0 + 1,
|
|
207
|
+
lists__length_generate(Xs, N1, N).
|
|
208
|
+
|
|
209
|
+
lists__integer(X) :- integer(X), !.
|
|
210
|
+
lists__integer(X) :- var(X), !, 0 is X.
|
|
211
|
+
% arg/3 performs the ISO integer type check before inspecting its term.
|
|
212
|
+
lists__integer(X) :- arg(X, type_check, _).
|
|
213
|
+
|
|
214
|
+
lists__not_less_than_zero(X) :- X >= 0, !.
|
|
215
|
+
% atom_length/2 reports domain_error(not_less_than_zero) for a negative value.
|
|
216
|
+
lists__not_less_than_zero(X) :- atom_length('', X).
|
|
193
217
|
|
|
194
218
|
lists__sum_list([], Sum, Sum).
|
|
195
219
|
lists__sum_list([X|Xs], Acc, Sum) :- Next is Acc + X, lists__sum_list(Xs, Next, Sum).
|
package/src/standard-library.js
CHANGED
|
@@ -109,6 +109,10 @@ export const eyePrologInteropAutoload = Object.freeze({
|
|
|
109
109
|
'foldl/6': 'lists',
|
|
110
110
|
'sum_list/2': 'lists',
|
|
111
111
|
'list_to_set/2': 'lists',
|
|
112
|
+
// call_nth/2 is available in both Trealla and Scryer (the latter via
|
|
113
|
+
// library(iso_ext)). EyeProlog keeps its adapter in library(prologue), so
|
|
114
|
+
// autoloading hides that implementation-specific location from source.
|
|
115
|
+
'call_nth/2': 'prologue',
|
|
112
116
|
// Trealla and Scryer expose between/3 without an EyeProlog-style
|
|
113
117
|
// library(prologue) dependency. EyeProlog keeps its implementation in the
|
|
114
118
|
// Prologue module but autoloads it so portable source need not name that
|
package/test/run-regression.mjs
CHANGED
|
@@ -2030,6 +2030,21 @@ c4 ?- call((!;1)).
|
|
|
2030
2030
|
assertEqual(result.stderr, '', 'stderr');
|
|
2031
2031
|
},
|
|
2032
2032
|
},
|
|
2033
|
+
{
|
|
2034
|
+
name: 'library(lists) length/2 stays relational and call_nth/2 autoloads (issue #28)',
|
|
2035
|
+
run: () => {
|
|
2036
|
+
const input = [
|
|
2037
|
+
':- use_module(library(lists)).',
|
|
2038
|
+
'%% goal: fourth_length(N)',
|
|
2039
|
+
'fourth_length(N) :- call_nth(length(_Xs, N), 4).',
|
|
2040
|
+
'',
|
|
2041
|
+
].join('\n');
|
|
2042
|
+
const result = runCli(['-'], { input });
|
|
2043
|
+
assertEqual(result.status, 0, 'exit status');
|
|
2044
|
+
assertEqual(result.stdout, 'fourth_length(3).\n', 'stdout');
|
|
2045
|
+
assertEqual(result.stderr, '', 'stderr');
|
|
2046
|
+
},
|
|
2047
|
+
},
|
|
2033
2048
|
{
|
|
2034
2049
|
name: 'strict ISO mode disables interop autoloading',
|
|
2035
2050
|
run: () => {
|
|
@@ -3433,10 +3448,11 @@ check(A, B, C, D, E, F) :-
|
|
|
3433
3448
|
assertEqual(Boolean(library.get('statistics', 2)), true, 'statistics/2 is an EyeProlog observability extension');
|
|
3434
3449
|
assertEqual(registeredNativeEyePrologLibraryNames().length, 40, 'public native EyeProlog builtin count');
|
|
3435
3450
|
assertEqual(eyePrologPortableLibraryIndicators.length, 62, 'portable Prolog library count');
|
|
3436
|
-
assertEqual(eyePrologInteropLibraryIndicators.length,
|
|
3451
|
+
assertEqual(eyePrologInteropLibraryIndicators.length, 27, 'cross-implementation interop profile count');
|
|
3437
3452
|
assertEqual(eyePrologInteropLibraryModules.join(','), 'lists', 'common explicit library module profile');
|
|
3438
3453
|
assertEqual(eyePrologInteropAutoload['member/2'], 'lists', 'member/2 canonical autoload');
|
|
3439
3454
|
assertEqual(eyePrologInteropAutoload['between/3'], 'prologue', 'between/3 canonical internal autoload');
|
|
3455
|
+
assertEqual(eyePrologInteropAutoload['call_nth/2'], 'prologue', 'call_nth/2 canonical internal autoload');
|
|
3440
3456
|
assertEqual(eyePrologInteropAutoload['set_nth0/4'] ?? null, null, 'EyeProlog-only set_nth0/4 is not autoloadable');
|
|
3441
3457
|
assertEqual(eyePrologNativeLibraryIndicators.length, 40, 'native host library count');
|
|
3442
3458
|
assertEqual(eyePrologNativeLibraryIndicators.slice(0, 2).join(','), 'call_nth/2,freeze/2', 'control predicates requiring host support');
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6037,17 +6037,21 @@ still have an API that is not shared by the other systems.
|
|
|
6037
6037
|
`library(lists)` is the first aligned common module. Its interop surface includes
|
|
6038
6038
|
`member/2`, `memberchk/2`, `select/3`, `append/2-3`, `last/2`,
|
|
6039
6039
|
`same_length/2`, `nth0/3-4`, `nth1/3-4`, `reverse/2`, `length/2`,
|
|
6040
|
-
`maplist/2-8`, `foldl/4-6`, `sum_list/2`, and `list_to_set/2`.
|
|
6041
|
-
|
|
6042
|
-
|
|
6040
|
+
`maplist/2-8`, `foldl/4-6`, `sum_list/2`, and `list_to_set/2`. Its `length/2`
|
|
6041
|
+
is fully relational: when both arguments are variables, `length(Xs, N)`
|
|
6042
|
+
enumerates `Xs = [], N = 0`, then one-element lists with `N = 1`, and so on.
|
|
6043
|
+
This generator mode is important for portable stress and enumeration programs.
|
|
6044
|
+
EyeProlog-only helpers such as `set_nth0/4`, `take/3`, `drop/3`, and `slice/4`
|
|
6045
|
+
remain available for compatibility but are outside this profile.
|
|
6043
6046
|
|
|
6044
6047
|
Normal EyeProlog execution can autoload an otherwise undefined unqualified call
|
|
6045
6048
|
only when the interop table assigns it one canonical provider. Thus `member/2`
|
|
6046
|
-
autoloads from `library(lists)`. `between/3`
|
|
6047
|
-
EyeProlog can satisfy
|
|
6048
|
-
without forcing portable source to mention
|
|
6049
|
-
name. Autoloading is disabled by
|
|
6050
|
-
`autoload: false`, and always by
|
|
6049
|
+
autoloads from `library(lists)`. `between/3` and `call_nth/2` are also in the
|
|
6050
|
+
interop profile; EyeProlog can satisfy them from its internal
|
|
6051
|
+
`library(prologue)` implementation without forcing portable source to mention
|
|
6052
|
+
that EyeProlog-specific library name. Autoloading is disabled by
|
|
6053
|
+
`--no-autoload`, by the JavaScript option `autoload: false`, and always by
|
|
6054
|
+
`--iso-strict`.
|
|
6051
6055
|
|
|
6052
6056
|
`-w` / `--warnings` reports explicit non-profile library dependencies and calls
|
|
6053
6057
|
to non-profile predicates from common libraries. `--portable` turns those
|