eyeprolog 1.1.11 → 1.1.12

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
@@ -91,12 +91,14 @@ noun --> [world] | [prolog].
91
91
  %% goal: phrase(sentence, Words)
92
92
  ```
93
93
 
94
- EyeProlog also adds 46 public library predicates to its 129-entry ISO registry.
95
- **All 46 are ordinary Prolog clauses** in `src/lib/eyeprolog.pl`,
96
- `src/lib/lists.pl`, and `src/lib/prologue.pl`. They are ISO/IEC 13211-2 modules,
94
+ EyeProlog also adds 57 public library predicate indicators to its 129-entry ISO
95
+ profile. **56 are implemented entirely as ordinary Prolog clauses** in
96
+ `src/lib/eyeprolog.pl`, `src/lib/lists.pl`, and `src/lib/prologue.pl`; the
97
+ `call_nth/2` module clause uses one private host adapter to number solutions.
98
+ They are ISO/IEC 13211-2 modules,
97
99
  loaded explicitly with `use_module(library(eyeprolog))`,
98
- `use_module(library(lists))`, or `use_module(library(prologue))`. None requires
99
- host support. Portable text predicates use ISO atoms or character lists.
100
+ `use_module(library(lists))`, or `use_module(library(prologue))`. Portable text
101
+ predicates use ISO atoms or character lists.
100
102
 
101
103
  ## Development
102
104
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.1.11",
6
+ "version": "1.1.12",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
package/src/iso.js CHANGED
@@ -164,6 +164,15 @@ export const isoBuiltins = {
164
164
  }
165
165
  };
166
166
 
167
+ // call_nth/2 is a Prologue library predicate with control behavior that cannot
168
+ // be expressed portably as ordinary Prolog clauses. Keep the public wrapper
169
+ // in library(prologue) and expose only this private adapter to the host registry.
170
+ export const eyePrologLibraryBuiltins = {
171
+ register(registry) {
172
+ registry.add('eyeprolog__call_nth', 2, callNthBuiltin, { eyePrologLibrary: true });
173
+ },
174
+ };
175
+
167
176
  function* unification({ goal, env }) {
168
177
  const next = env.clone();
169
178
  if (unify(goal.args[0], goal.args[1], next)) yield next;
@@ -1564,6 +1573,36 @@ function* callClosureBuiltin({ solver, goal, env }) {
1564
1573
  }
1565
1574
  }
1566
1575
 
1576
+ function* callNthBuiltin({ solver, goal, env }) {
1577
+ const requestedTerm = deref(goal.args[1], env);
1578
+ // Zero is the one Nth value that fails before Goal is inspected.
1579
+ if (requestedTerm.type === NUMBER && isDecimalInteger(requestedTerm.name) && BigInt(requestedTerm.name) === 0n) return;
1580
+
1581
+ const invoked = callable(goal.args[0], env);
1582
+ let requested = null;
1583
+ if (requestedTerm.type !== VAR) {
1584
+ if (requestedTerm.type !== NUMBER || !isDecimalInteger(requestedTerm.name)) {
1585
+ throw new PrologError('type_error(integer)', requestedTerm);
1586
+ }
1587
+ requested = BigInt(requestedTerm.name);
1588
+ if (requested < 0n) throw new PrologError('domain_error(not_less_than_zero)', requestedTerm);
1589
+ }
1590
+
1591
+ const child = solver.cloneForInnerGoal();
1592
+ let nth = 0n;
1593
+ try {
1594
+ for (const answerEnv of child.solve([invoked], env, 0)) {
1595
+ nth++;
1596
+ if (requested != null && nth < requested) continue;
1597
+ const next = answerEnv.clone();
1598
+ if (unify(goal.args[1], numberTerm(nth.toString()), next)) yield next;
1599
+ if (requested != null) return;
1600
+ }
1601
+ } finally {
1602
+ solver.absorbStatsFrom(child);
1603
+ }
1604
+ }
1605
+
1567
1606
  function* phraseBuiltin({ solver, goal, env }) {
1568
1607
  const grammarBody = deref(goal.args[0], env);
1569
1608
  if (grammarBody.type === VAR) throw new PrologError('instantiation_error');
@@ -7,10 +7,36 @@
7
7
  between/3,
8
8
  select/3,
9
9
  succ/2,
10
- maplist/2
10
+ maplist/2,
11
+ maplist/3,
12
+ maplist/4,
13
+ maplist/5,
14
+ maplist/6,
15
+ maplist/7,
16
+ maplist/8,
17
+ nth0/3,
18
+ nth0/4,
19
+ nth1/3,
20
+ nth1/4,
21
+ call_nth/2,
22
+ foldl/4,
23
+ foldl/5,
24
+ foldl/6,
25
+ countall/2
11
26
  ]).
12
27
 
13
28
  :- meta_predicate(maplist(1, '?')).
29
+ :- meta_predicate(maplist(2, '?', '?')).
30
+ :- meta_predicate(maplist(3, '?', '?', '?')).
31
+ :- meta_predicate(maplist(4, '?', '?', '?', '?')).
32
+ :- meta_predicate(maplist(5, '?', '?', '?', '?', '?')).
33
+ :- meta_predicate(maplist(6, '?', '?', '?', '?', '?', '?')).
34
+ :- meta_predicate(maplist(7, '?', '?', '?', '?', '?', '?', '?')).
35
+ :- meta_predicate(call_nth(0, '?')).
36
+ :- meta_predicate(foldl(3, '?', '?', '?')).
37
+ :- meta_predicate(foldl(4, '?', '?', '?', '?')).
38
+ :- meta_predicate(foldl(5, '?', '?', '?', '?', '?')).
39
+ :- meta_predicate(countall(0, '?')).
14
40
 
15
41
  member(X, [X|_]).
16
42
  member(X, [_|Xs]) :- member(X, Xs).
@@ -74,6 +100,84 @@ maplist(Closure, [X|Xs]) :-
74
100
  call(Closure, X),
75
101
  maplist(Closure, Xs).
76
102
 
103
+ maplist(_, [], []).
104
+ maplist(Closure, [A|As], [B|Bs]) :-
105
+ call(Closure, A, B),
106
+ maplist(Closure, As, Bs).
107
+
108
+ maplist(_, [], [], []).
109
+ maplist(Closure, [A|As], [B|Bs], [C|Cs]) :-
110
+ call(Closure, A, B, C),
111
+ maplist(Closure, As, Bs, Cs).
112
+
113
+ maplist(_, [], [], [], []).
114
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds]) :-
115
+ call(Closure, A, B, C, D),
116
+ maplist(Closure, As, Bs, Cs, Ds).
117
+
118
+ maplist(_, [], [], [], [], []).
119
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es]) :-
120
+ call(Closure, A, B, C, D, E),
121
+ maplist(Closure, As, Bs, Cs, Ds, Es).
122
+
123
+ maplist(_, [], [], [], [], [], []).
124
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs]) :-
125
+ call(Closure, A, B, C, D, E, F),
126
+ maplist(Closure, As, Bs, Cs, Ds, Es, Fs).
127
+
128
+ maplist(_, [], [], [], [], [], [], []).
129
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs], [G|Gs]) :-
130
+ call(Closure, A, B, C, D, E, F, G),
131
+ maplist(Closure, As, Bs, Cs, Ds, Es, Fs, Gs).
132
+
133
+ nth0(N, List, Elem) :- nth0(N, List, Elem, _).
134
+
135
+ nth0(N, List, Elem, Rest) :-
136
+ prologue__integer_or_variable(N),
137
+ ( var(N) -> prologue__nth0(N, List, Elem, Rest)
138
+ ; prologue__not_less_than_zero(N),
139
+ prologue__nth0(N, List, Elem, Rest)
140
+ ).
141
+
142
+ prologue__nth0(0, [Elem|Rest], Elem, Rest).
143
+ prologue__nth0(N, [X|Xs], Elem, [X|Rest]) :-
144
+ var(N),
145
+ prologue__nth0(N0, Xs, Elem, Rest),
146
+ N is N0 + 1.
147
+ prologue__nth0(N, [X|Xs], Elem, [X|Rest]) :-
148
+ nonvar(N),
149
+ N > 0,
150
+ N0 is N - 1,
151
+ prologue__nth0(N0, Xs, Elem, Rest).
152
+
153
+ nth1(N, List, Elem) :- nth1(N, List, Elem, _).
154
+
155
+ nth1(N, List, Elem, Rest) :-
156
+ N \== 0,
157
+ nth0(N, [_|List], Elem, [_|Rest]),
158
+ N \== 0.
159
+
160
+ call_nth(Goal, Nth) :- eyeprolog__call_nth(Goal, Nth).
161
+
162
+ foldl(_, [], Acc, Acc).
163
+ foldl(Closure, [A|As], Acc0, Acc) :-
164
+ call(Closure, A, Acc0, Acc1),
165
+ foldl(Closure, As, Acc1, Acc).
166
+
167
+ foldl(_, [], [], Acc, Acc).
168
+ foldl(Closure, [A|As], [B|Bs], Acc0, Acc) :-
169
+ call(Closure, A, B, Acc0, Acc1),
170
+ foldl(Closure, As, Bs, Acc1, Acc).
171
+
172
+ foldl(_, [], [], [], Acc, Acc).
173
+ foldl(Closure, [A|As], [B|Bs], [C|Cs], Acc0, Acc) :-
174
+ call(Closure, A, B, C, Acc0, Acc1),
175
+ foldl(Closure, As, Bs, Cs, Acc1, Acc).
176
+
177
+ countall(Goal, Count) :-
178
+ findall(1, Goal, Ones),
179
+ length(Ones, Count).
180
+
77
181
  prologue__integer_or_variable(X) :- var(X), !.
78
182
  prologue__integer_or_variable(X) :- prologue__integer(X).
79
183
 
@@ -2,7 +2,7 @@
2
2
  // The sources are registered here so library(Name) works in Node and browsers;
3
3
  // unlike the former autoloader, no clauses are added unless use_module/1 or
4
4
  // use_module/2 requests their module.
5
- import { createDefaultRegistry } from './iso.js';
5
+ import { createDefaultRegistry, eyePrologLibraryBuiltins } from './iso.js';
6
6
  import { fs, isNode } from './platform.js';
7
7
 
8
8
  const moduleFiles = Object.freeze({
@@ -35,21 +35,27 @@ function libraryUrl(filename) {
35
35
  return url;
36
36
  }
37
37
 
38
- export const eyePrologNativeLibraryIndicators = Object.freeze([]);
38
+ export const eyePrologNativeLibraryIndicators = Object.freeze(['call_nth/2']);
39
39
  export const eyePrologPortableLibraryIndicators = Object.freeze([
40
- 'uuid/3', 'difference/3', 'maplist/2', 'maplist/3', 'lt/2', 'gt/2', 'le/2', 'ge/2',
40
+ 'uuid/3', 'difference/3', 'maplist/2', 'maplist/3', 'maplist/4', 'maplist/5',
41
+ 'maplist/6', 'maplist/7', 'maplist/8', 'lt/2', 'gt/2', 'le/2', 'ge/2',
41
42
  'between/3', 'smallest_divisor_from/3', 'random/3', 'matches/3', 'split/3',
42
43
  'replace/4', 'lowercase/2', 'uppercase/2', 'trim/2', 'number_string/2',
43
44
  'atom_string/2', 'term_string/2', 'append/3', 'string_concat/3', 'contains/2',
44
45
  'matches/2', 'join/3', 'substring/4', 'member/2', 'select/3', 'last/2',
45
- 'nth0/3', 'nth1/3', 'set_nth0/4', 'take/3', 'drop/3', 'slice/4', 'reverse/2',
46
+ 'nth0/3', 'nth0/4', 'nth1/3', 'nth1/4', 'set_nth0/4', 'take/3', 'drop/3', 'slice/4', 'reverse/2',
46
47
  'length/2', 'sum_list/2', 'min_list/2', 'max_list/2', 'list_to_set/2',
47
- 'countall/2', 'succ/2', 'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
48
+ 'countall/2', 'succ/2', 'foldl/4', 'foldl/5', 'foldl/6',
49
+ 'sumall/3', 'aggregate_min/5', 'aggregate_max/5',
50
+ ]);
51
+ export const eyePrologLibraryIndicators = Object.freeze([
52
+ ...eyePrologPortableLibraryIndicators,
53
+ ...eyePrologNativeLibraryIndicators,
48
54
  ]);
49
- export const eyePrologLibraryIndicators = Object.freeze([...eyePrologPortableLibraryIndicators]);
50
55
 
51
56
  export function createEyePrologRegistry() {
52
57
  const registry = createDefaultRegistry();
58
+ eyePrologLibraryBuiltins.register(registry);
53
59
  registry.eyePrologLibrary = true;
54
60
  return registry;
55
61
  }
@@ -0,0 +1,32 @@
1
+ ?- call_nth(true, Nth).
2
+ Nth = 1.
3
+ ?- call_nth(false, Nth).
4
+ false.
5
+ ?- call_nth(repeat, Nth).
6
+ Nth = 1
7
+ ; Nth = 2
8
+ ; Nth = 3
9
+ ; Nth = 4
10
+ ; Nth = 5
11
+ ; ... .
12
+ ?- call_nth(( N = 1 ; N = 2 ), Nth).
13
+ N = 1, Nth = 1
14
+ ; N = 2, Nth = 2.
15
+ ?- call_nth(true, non_integer).
16
+ type_error(integer,non_integer).
17
+ ?- call_nth(true, 1.0).
18
+ type_error(integer,1.0).
19
+ ?- call_nth(true, 0).
20
+ false.
21
+ ?- call_nth(repeat, 0).
22
+ false.
23
+ ?- call_nth(repeat, -1).
24
+ domain_error(not_less_than_zero,-1).
25
+ ?- call_nth(length(L,N), 3).
26
+ L = [_A,_B], N = 2.
27
+ ?- call_nth(inex, 0).
28
+ false.
29
+ ?- call_nth(1, 0).
30
+ false.
31
+ ?- call_nth(V, 0).
32
+ false.
@@ -0,0 +1,2 @@
1
+ :- use_module(library(prologue)).
2
+ :- include('prologue_call_nth_quad.pl').
@@ -0,0 +1,87 @@
1
+ % Finite examples and arity coverage for Prologue p.p.7 through p.p.11.
2
+
3
+ ?- maplist(same2, [a], [a]).
4
+ true.
5
+ ?- maplist(same3, [a], [a], [a]).
6
+ true.
7
+ ?- maplist(same4, [a], [a], [a], [a]).
8
+ true.
9
+ ?- maplist(same5, [a], [a], [a], [a], [a]).
10
+ true.
11
+ ?- maplist(same6, [a], [a], [a], [a], [a], [a]).
12
+ true.
13
+ ?- maplist(same7, [a], [a], [a], [a], [a], [a], [a]).
14
+ true.
15
+
16
+ ?- nth0(1, [a,b,c], E).
17
+ E = b.
18
+ ?- nth0(N, [a,b,c], E).
19
+ N = 0, E = a
20
+ ; N = 1, E = b
21
+ ; N = 2, E = c.
22
+ ?- nth0(0, [A,B|non_list], E).
23
+ A = E.
24
+ ?- nth0(2, Es, E).
25
+ Es = [_A,_B,E|_C].
26
+ ?- nth0(N, Es, E).
27
+ N = 0, Es = [E|_A]
28
+ ; N = 1, Es = [_A,E|_B]
29
+ ; N = 2, Es = [_A,_B,E|_C]
30
+ ; N = 3, Es = [_A,_B,_C,E|_D]
31
+ ; ... .
32
+ ?- nth0(non_integer, Es, E).
33
+ type_error(integer, non_integer).
34
+ ?- nth0(-1, Es, E).
35
+ domain_error(not_less_than_zero, -1).
36
+ ?- nth0(N, [[]|Es], Es).
37
+ N = 0, Es = []
38
+ ; sto, loops.
39
+ ?- nth0(1, [a,b,c], E, Es).
40
+ E = b, Es = [a,c].
41
+ ?- nth1(0, Es, E).
42
+ false.
43
+ ?- nth1(2, [a,b,c], E, Es).
44
+ E = b, Es = [a,c].
45
+
46
+ ?- call_nth(N = 1, N).
47
+ N = 1.
48
+ ?- call_nth(N = -1, N).
49
+ false.
50
+ ?- call_nth(repeat, 1+1).
51
+ type_error(integer, 1+1).
52
+ ?- call_nth(inex, 0).
53
+ existence_error(procedure, _), unexpected.
54
+ ?- call_nth(G, non_integer).
55
+ instantiation_error.
56
+ ?- call_nth(1, -1).
57
+ type_error(callable, 1).
58
+
59
+ ?- foldl(append, [[1,2],[3],[4,5]], [], Xs).
60
+ Xs = [4,5,3,1,2].
61
+ ?- foldl(add2, [1,2], [10,20], 0, S).
62
+ S = 33.
63
+ ?- foldl(add3, [1,2], [10,20], [100,200], 0, S).
64
+ S = 333.
65
+
66
+ ?- countall((X=1;X=2), N).
67
+ N = 2.
68
+ ?- countall((true;true), N).
69
+ N = 2.
70
+ ?- countall(G, N).
71
+ instantiation_error.
72
+ ?- countall((length(L,5),nth0(_,L,_),nth0(_,L,_)), N).
73
+ N = 25.
74
+ ?- countall(N=1, N).
75
+ N = 1.
76
+ ?- countall(N=non_integer, N).
77
+ N = 1.
78
+ ?- countall(false, 1).
79
+ false.
80
+ ?- countall(false, -1).
81
+ domain_error(not_less_than_zero, -1).
82
+ ?- countall(false, non_integer).
83
+ type_error(integer, non_integer).
84
+ ?- countall(G, -1).
85
+ instantiation_error.
86
+ ?- countall(1, -1).
87
+ type_error(callable, 1).
@@ -0,0 +1,13 @@
1
+ :- use_module(library(prologue)).
2
+
3
+ same2(X, X).
4
+ same3(X, X, X).
5
+ same4(X, X, X, X).
6
+ same5(X, X, X, X, X).
7
+ same6(X, X, X, X, X, X).
8
+ same7(X, X, X, X, X, X, X).
9
+
10
+ add2(X, Y, S0, S) :- S is S0 + X + Y.
11
+ add3(X, Y, Z, S0, S) :- S is S0 + X + Y + Z.
12
+
13
+ :- include('prologue_extended_quad.pl').
@@ -50,7 +50,7 @@ const bin = path.join(packageRoot, 'bin', 'eyeprolog.js');
50
50
  const pkg = JSON.parse(fs.readFileSync(path.join(packageRoot, 'package.json'), 'utf8'));
51
51
  let tmp = null;
52
52
  let tmpCounter = 0;
53
- const libraryCall = /\b(?:uuid|difference|maplist|lt|gt|le|ge|between|smallest_divisor_from|random|matches|split|replace|lowercase|uppercase|trim|number_string|atom_string|term_string|append|string_concat|contains|join|substring|member|select|last|nth0|nth1|set_nth0|take|drop|slice|reverse|length|sum_list|min_list|max_list|list_to_set|countall|sumall|aggregate_min|aggregate_max)\s*\(/;
53
+ const libraryCall = /\b(?:uuid|difference|maplist|foldl|call_nth|lt|gt|le|ge|between|smallest_divisor_from|random|matches|split|replace|lowercase|uppercase|trim|number_string|atom_string|term_string|append|string_concat|contains|join|substring|member|select|last|nth0|nth1|set_nth0|take|drop|slice|reverse|length|sum_list|min_list|max_list|list_to_set|countall|sumall|aggregate_min|aggregate_max)\s*\(/;
54
54
 
55
55
  function withStandardModules(source) {
56
56
  if (!libraryCall.test(source) || source.includes('use_module(library(') || source.includes(':- module(')) return source;
@@ -337,6 +337,36 @@ c4 ?- call((!;1)).
337
337
  assertEqual(result.stdout, 'quads: 33 run, 33 passed, 0 failed.\n', 'quad report');
338
338
  },
339
339
  },
340
+ {
341
+ name: 'runQuads passes the authoritative Prologue call_nth quad corpus',
342
+ run: () => {
343
+ const filename = path.join(testRoot, 'fixtures', 'prologue_call_nth_quad_runner.pl');
344
+ const source = fs.readFileSync(filename, 'utf8');
345
+ const result = publicApi.runQuads(Program.parseSources([{
346
+ text: source,
347
+ filename,
348
+ baseDir: path.dirname(filename),
349
+ }]));
350
+ assertEqual(result.total, 13, 'quad total');
351
+ assertEqual(result.passed, 13, 'quad passed');
352
+ assertEqual(result.stdout, 'quads: 13 run, 13 passed, 0 failed.\n', 'quad report');
353
+ },
354
+ },
355
+ {
356
+ name: 'runQuads covers the remaining finite Prologue examples and arities',
357
+ run: () => {
358
+ const filename = path.join(testRoot, 'fixtures', 'prologue_extended_quad_runner.pl');
359
+ const source = fs.readFileSync(filename, 'utf8');
360
+ const result = publicApi.runQuads(Program.parseSources([{
361
+ text: source,
362
+ filename,
363
+ baseDir: path.dirname(filename),
364
+ }]));
365
+ assertEqual(result.total, 37, 'quad total');
366
+ assertEqual(result.passed, 37, 'quad passed');
367
+ assertEqual(result.stdout, 'quads: 37 run, 37 passed, 0 failed.\n', 'quad report');
368
+ },
369
+ },
340
370
  {
341
371
  name: 'runQuads rejects malformed answer substitutions',
342
372
  run: () => {
@@ -1348,14 +1378,17 @@ open(X) :- candidate(X), \\+ closed(X).
1348
1378
  assertEqual(Boolean(registry.get('is', 2)), true, 'ISO is/2 exists');
1349
1379
  assertEqual(Boolean(registry.get('append', 3)), false, 'append/3 is not ISO core');
1350
1380
  assertEqual(library.eyePrologLibrary, true, 'complete registry marker');
1351
- assertEqual(library.defs.size, 129, 'EyeProlog registry contains only ISO host definitions');
1381
+ assertEqual(library.defs.size, 130, 'EyeProlog registry contains ISO definitions and one private library adapter');
1352
1382
  assertEqual(Boolean(registry.get('phrase', 2)), true, 'Part 3 phrase/2 exists');
1353
1383
  assertEqual(Boolean(registry.get('phrase', 3)), true, 'Part 3 phrase/3 exists');
1354
- assertEqual(registeredNativeEyePrologLibraryNames().length, 0, 'public native EyeProlog builtin count');
1355
- assertEqual(eyePrologPortableLibraryIndicators.length, 46, 'portable Prolog library count');
1356
- assertEqual(eyePrologNativeLibraryIndicators.length, 0, 'native host library count');
1357
- assertEqual(eyePrologNativeLibraryIndicators.join(','), '', 'no EyeProlog library predicate requires host support');
1358
- assertEqual(eyePrologLibraryIndicators.length, 46, 'complete EyeProlog library surface');
1384
+ assertEqual(registeredNativeEyePrologLibraryNames().length, 1, 'public native EyeProlog builtin count');
1385
+ assertEqual(eyePrologPortableLibraryIndicators.length, 56, 'portable Prolog library count');
1386
+ assertEqual(eyePrologNativeLibraryIndicators.length, 1, 'native host library count');
1387
+ assertEqual(eyePrologNativeLibraryIndicators.join(','), 'call_nth/2', 'control predicate requiring host support');
1388
+ assertEqual(eyePrologLibraryIndicators.length, 57, 'complete EyeProlog library surface');
1389
+ assertEqual(registry.get('eyeprolog__call_nth', 2), null, 'private call_nth adapter is absent from ISO registry');
1390
+ assertEqual(Boolean(library.get('eyeprolog__call_nth', 2)), true, 'private call_nth adapter is registered for EyeProlog');
1391
+ assertEqual(library.get('eyeprolog__call_nth', 2)?.eyePrologLibrary, true, 'private adapter is marked as library support');
1359
1392
  assertEqual(library.get('between', 3), null, 'between/3 remains portable Prolog');
1360
1393
  assertEqual(library.get('smallest_divisor_from', 3), null, 'smallest_divisor_from/3 remains portable Prolog');
1361
1394
  assertEqual(library.get('random', 3), null, 'random/3 remains portable Prolog');
@@ -5761,22 +5761,25 @@ so side effects occur in Prolog execution order.
5761
5761
 
5762
5762
  ### The EyeProlog library
5763
5763
 
5764
- EyeProlog exposes **46 library predicate indicators** in addition to the 129
5765
- indicators in its isolated ISO profile. **All 46 are ordinary Prolog clauses**
5766
- across `src/lib/eyeprolog.pl`, `src/lib/lists.pl`, and `src/lib/prologue.pl`; none
5767
- is a native host predicate. The resulting
5768
- normal EyeProlog language surface is therefore **175 public predicate
5769
- indicators**. Internally, the runtime registry contains only the 129 ISO
5770
- definitions; the EyeProlog relations are module source clauses.
5764
+ EyeProlog exposes **57 library predicate indicators** in addition to the 129
5765
+ indicators in its isolated ISO profile. **56 are implemented entirely as
5766
+ ordinary Prolog clauses** across `src/lib/eyeprolog.pl`, `src/lib/lists.pl`, and
5767
+ `src/lib/prologue.pl`. The Prologue `call_nth/2` clause delegates its solution
5768
+ numbering to one private host adapter. The resulting normal EyeProlog language
5769
+ surface is therefore **186 public predicate indicators**. Internally, the
5770
+ runtime registry contains the 129 ISO definitions plus that private adapter;
5771
+ the remaining EyeProlog relations are module source clauses.
5771
5772
 
5772
5773
  The three Prolog files declare `eyeprolog`, `lists`, and `prologue` with
5773
5774
  `module/2`. A program loads them explicitly with
5774
5775
  `use_module(library(eyeprolog))`, `use_module(library(lists))`, or
5775
5776
  `use_module(library(prologue))`; `use_module/2` can select a smaller import
5776
- list. The last module implements the predicates exercised by the working-draft
5777
- Prologue quad corpus.
5778
- `src/standard-library.js` only registers the module sources for Node and browser
5779
- resolution and never adds clauses implicitly.
5777
+ list. The last module implements p.p.1 through p.p.11 of the
5778
+ [working-draft Prologue](https://www.complang.tuwien.ac.at/ulrich/iso-prolog/prologue),
5779
+ with the published `call_nth/2` quads and finite examples retained as offline
5780
+ regressions. `src/standard-library.js` registers the module sources and private
5781
+ control adapter for Node and browser resolution, and never adds clauses
5782
+ implicitly.
5780
5783
  The isolated ISO-only registry remains
5781
5784
  available through `createDefaultRegistry()` and `getDefaultRegistry()` for
5782
5785
  conformance work and advanced embedders. Module-local predicate identity keeps
@@ -5788,7 +5791,7 @@ private helpers and same-named predicates in different modules separate.
5788
5791
  | --- | --- |
5789
5792
  | `library(lists)` | `maplist/3`, `append/3`, `member/2`, `select/3`, `last/2`, `nth0/3`, `nth1/3`, `reverse/2`, `length/2`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `countall/2` |
5790
5793
  | `library(eyeprolog)` | `uuid/3`, `difference/3`, `lt/2`, `le/2`, `gt/2`, `ge/2`, `between/3`, `smallest_divisor_from/3`, `random/3`, `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`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4`, `sumall/3`, `aggregate_min/5`, `aggregate_max/5` |
5791
- | `library(prologue)` | `member/2`, `append/3`, `length/2`, `between/3`, `select/3`, `succ/2`, `maplist/2` |
5794
+ | `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`, `foldl/4`, `foldl/5`, `foldl/6`, `countall/2` |
5792
5795
 
5793
5796
  <!-- eyeprolog-library-catalog:end -->
5794
5797
 
@@ -5915,7 +5918,7 @@ eyeprolog --goal 'answer(Kind, Value)' program.pl
5915
5918
  The portable text API uses **ISO atoms or proper lists of one-character atoms**.
5916
5919
  A generated text result defaults to an atom. Double-quoted source text uses the
5917
5920
  ISO representation selected by `double_quotes`; with the default `chars`, it is
5918
- already a proper character list accepted by this API. The 46-predicate portable
5921
+ already a proper character list accepted by this API. The 56-predicate portable
5919
5922
  library itself has no STRING or JavaScript dependency.
5920
5923
 
5921
5924
  | Predicate and principal mode | Behavior |