eyeprolog 1.3.75 → 1.3.77

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.
Files changed (40) hide show
  1. package/README.md +6 -6
  2. package/examples/binomial-vandermonde.pl +1 -1
  3. package/examples/book/chapter-26/02-triple.pl +1 -1
  4. package/examples/book/chapter-28/02-triangle.pl +1 -1
  5. package/examples/book/chapter-28/04-integer_rectangle.pl +1 -1
  6. package/examples/book/chapter-29/01-counterexample_to_odd_square.pl +1 -1
  7. package/examples/book/chapter-31/03-double.pl +1 -1
  8. package/examples/book/chapter-32/04-reference_square.pl +1 -1
  9. package/examples/book/chapter-33/03-chosen_pair.pl +1 -1
  10. package/examples/book/chapter-39/01-answer.pl +1 -1
  11. package/examples/catalan-convolution.pl +1 -1
  12. package/examples/collatz-1000.pl +1 -1
  13. package/examples/continued-fraction-sqrt2.pl +1 -1
  14. package/examples/easter-computus.pl +1 -1
  15. package/examples/equality-saturation.pl +1 -1
  16. package/examples/goldbach.pl +1 -1
  17. package/examples/integer-partitions.pl +1 -1
  18. package/examples/job-shop-scheduling.pl +1 -1
  19. package/examples/matrix-chain-order.pl +1 -1
  20. package/examples/missionaries-cannibals.pl +1 -1
  21. package/examples/pell-equation.pl +1 -1
  22. package/examples/polynomial.pl +1 -1
  23. package/examples/prime-range.pl +1 -1
  24. package/examples/stirling-bell-numbers.pl +1 -1
  25. package/examples/totient-summatory.pl +1 -1
  26. package/package.json +1 -1
  27. package/src/iso.js +42 -17
  28. package/src/lib/lists.pl +15 -5
  29. package/src/lib/prologue.pl +30 -166
  30. package/src/program.js +20 -8
  31. package/src/quads.js +24 -3
  32. package/src/repl.js +10 -2
  33. package/src/solver.js +5 -5
  34. package/src/standard-library.js +5 -6
  35. package/src/term.js +4 -3
  36. package/test/fixtures/README.md +8 -0
  37. package/test/fixtures/variable_names_quad.pl +163 -0
  38. package/test/run-regression.mjs +88 -7
  39. package/test/test-support.mjs +1 -1
  40. package/the-art-of-eyeprolog.md +30 -23
package/README.md CHANGED
@@ -335,10 +335,11 @@ may be imported explicitly, while source/CLI/API dependency loading can resolve
335
335
  their unqualified forms conservatively. For Trealla-style interactive timing,
336
336
  `time/1` is also available directly in the normal EyeProlog runtime; strict ISO
337
337
  mode does not expose it.
338
- The aligned `library(lists)` and `library(iso_ext)` exports are kept disjoint so
339
- they can be imported together without an accidental import conflict. EyeProlog's
340
- legacy `library(prologue)` remains a compatibility umbrella and should be
341
- selectively imported when mixed with the aligned modules.
338
+ `library(lists)`, `library(iso_ext)`, and `library(freeze)` follow the focused
339
+ module organization used by Trealla and Scryer. EyeProlog's legacy
340
+ `library(prologue)` is now a compatibility facade over these canonical modules
341
+ and `library(between)`, so it can be imported before or after the focused
342
+ libraries without duplicate-import errors.
342
343
 
343
344
  `library(lambda)` follows Scryer's higher-order lambda notation, adapted from
344
345
  Ulrich Neumerkel's permissively licensed implementation. Importing it installs
@@ -362,8 +363,7 @@ Outside `--iso-strict`, an otherwise undefined unqualified call may autoload a
362
363
  predicate only when the interop profile has one canonical EyeProlog provider.
363
364
  For example, `member/2` autoloads from `library(lists)`, `call_nth/2` from
364
365
  `library(iso_ext)`, `call_residue_vars/2` from `library(atts)`, and `between/3`
365
- from EyeProlog's internal
366
- `library(prologue)` implementation. Use `--no-autoload` to disable this
366
+ from `library(between)`. Use `--no-autoload` to disable this
367
367
  convenience. Strict ISO mode never autoloads library predicates.
368
368
 
369
369
  Use `-w` / `--warnings` to diagnose dependencies outside the interop profile,
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Binomial coefficients and Vandermonde's identity.
5
5
  %
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 26 — Answers are existential witnesses.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  triple(A, B, C) :-
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 28 — Symmetry reduces search.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  triangle(A, B, C) :-
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 28.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  integer_rectangle(Area, W, H) :-
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 29 — Examples suggest; proofs compel.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  counterexample_to_odd_square(N) :-
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 31 — Properties over finite domains.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  double(N, D) :- (D is N + N).
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 32 — Compare specification and implementation.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  reference_square(N, S) :-
@@ -1,5 +1,5 @@
1
1
  % From The Art of EyeProlog, Chapter 33 — Pattern 3: Generate, constrain, describe.
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
 
5
5
  chosen_pair(pair(X, Y), reason(sum_is_ten)) :-
@@ -1,6 +1,6 @@
1
1
  % From The Art of EyeProlog, Chapter 39 — The EyeProlog library.
2
2
  :- use_module(library(dates)).
3
- :- use_module(library(prologue), [between/3]).
3
+ :- use_module(library(between), [between/3]).
4
4
  :- use_module(library(random)).
5
5
  :- use_module(library(lists)).
6
6
 
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Catalan numbers by automatically tabled convolution.
5
5
  %
@@ -1,4 +1,4 @@
1
- :- use_module(library(prologue), [between/3]).
1
+ :- use_module(library(between), [between/3]).
2
2
 
3
3
  % Collatz conjecture suite translated from Eyeling's examples/collatz-1000.n3.
4
4
  % It enumerates starts N = 1000, 999, ..., 1 by deriving N = 1000 - N0
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Convergents of sqrt(2) by automatically tabled recurrence.
5
5
  %
@@ -1,4 +1,4 @@
1
- :- use_module(library(prologue), [between/3]).
1
+ :- use_module(library(between), [between/3]).
2
2
 
3
3
  % Gregorian Easter computus adapted from Eyeling's easter.n3.
4
4
  % Each case is a year in a sample decade. The rules derive the Meeus/Jones/
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
  :- use_module(library(iso_ext)).
5
5
 
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(primes)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Goldbach's_conjecture
5
5
  % See https://en.wikipedia.org/wiki/Goldbach%27s_conjecture:
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Integer partition counts by tabled dynamic programming.
5
5
  %
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
  :- use_module(library(iso_ext)).
5
5
 
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
  :- use_module(library(iso_ext)).
5
5
 
@@ -1,4 +1,4 @@
1
- :- use_module(library(prologue), [between/3]).
1
+ :- use_module(library(between), [between/3]).
2
2
  :- use_module(library(lists)).
3
3
  :- use_module(library(iso_ext)).
4
4
 
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Pell equation x^2 - 2y^2 = 1 by automatically tabled recurrence.
5
5
  %
@@ -1,4 +1,4 @@
1
- :- use_module(library(prologue), [between/3]).
1
+ :- use_module(library(between), [between/3]).
2
2
  :- use_module(library(lists)).
3
3
 
4
4
  % Polynomial roots over complex integer candidates, adapted from Eyelet's
@@ -1,4 +1,4 @@
1
- :- use_module(library(prologue), [between/3]).
1
+ :- use_module(library(between), [between/3]).
2
2
  :- use_module(library(lists)).
3
3
  :- use_module(library(iso_ext)).
4
4
 
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
 
4
4
  % Stirling numbers of the second kind and Bell numbers.
5
5
  %
@@ -1,5 +1,5 @@
1
1
  :- use_module(library(aggregate)).
2
- :- use_module(library(prologue), [between/3]).
2
+ :- use_module(library(between), [between/3]).
3
3
  :- use_module(library(lists)).
4
4
  :- use_module(library(iso_ext)).
5
5
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.75",
6
+ "version": "1.3.77",
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
@@ -202,7 +202,12 @@ function difConstraint(left, right) {
202
202
  status(env) {
203
203
  if (identical(left, right, env)) return 'violated';
204
204
  const probe = env.clone();
205
- return unify(left, right, probe, { skipVariableConstraints: true }) ? 'pending' : 'entailed';
205
+ // Test structural unifiability without waking freeze/2 or other
206
+ // attributed-variable hooks in this disposable environment.
207
+ return unify(left, right, probe, {
208
+ skipVariableConstraints: true,
209
+ skipAttributeHooks: true,
210
+ }) ? 'pending' : 'entailed';
206
211
  },
207
212
  residualGoal() {
208
213
  return compound('dif', [left, right]);
@@ -218,8 +223,12 @@ function* difBuiltin({ goal, env }) {
218
223
  // In EyeProlog's finite-tree model, terms that cannot unify are already
219
224
  // provably different and need no residual constraint. Otherwise attach a
220
225
  // disequality constraint to every currently unbound variable it mentions.
226
+ // This probe must not wake goals attached to those variables.
221
227
  const probe = env.clone();
222
- if (!unify(left, right, probe, { skipVariableConstraints: true })) {
228
+ if (!unify(left, right, probe, {
229
+ skipVariableConstraints: true,
230
+ skipAttributeHooks: true,
231
+ })) {
223
232
  yield env;
224
233
  return;
225
234
  }
@@ -1577,23 +1586,39 @@ function readTermFromStream(stream, solver) {
1577
1586
  let requestedInteractiveTerm = false;
1578
1587
  while (true) {
1579
1588
  let sawCandidate = false;
1580
- for (const candidate of termTextCandidates(stream, solver)) {
1581
- sawCandidate = true;
1582
- if (candidate.lexicalError) {
1583
- stream.position = candidate.end;
1584
- throw new PrologError('syntax_error(read_term)');
1585
- }
1586
- try {
1587
- const term = parseReadTermText(candidate.text, solver);
1588
- stream.position = candidate.end;
1589
- return scopeReadTerm(term);
1590
- } catch (error) {
1591
- if (error instanceof NumberRepresentationError || error instanceof CharacterRepresentationError) {
1592
- throw new PrologError(error.formal);
1589
+ let lastCandidateEnd = stream.position;
1590
+ try {
1591
+ for (const candidate of termTextCandidates(stream, solver)) {
1592
+ sawCandidate = true;
1593
+ lastCandidateEnd = candidate.end;
1594
+ if (candidate.lexicalError) {
1595
+ stream.position = candidate.end;
1596
+ throw new PrologError('syntax_error(read_term)');
1597
+ }
1598
+ try {
1599
+ const term = parseReadTermText(candidate.text, solver);
1600
+ stream.position = candidate.end;
1601
+ return scopeReadTerm(term);
1602
+ } catch (error) {
1603
+ if (error instanceof NumberRepresentationError || error instanceof CharacterRepresentationError) {
1604
+ throw new PrologError(error.formal);
1605
+ }
1606
+ // A dot inside a graphic operator, such as =.., is only a possible
1607
+ // terminator. Keep scanning until a complete term parses.
1593
1608
  }
1594
- // A dot inside a graphic operator, such as =.., is only a possible
1595
- // terminator. Keep scanning until a complete term parses.
1596
1609
  }
1610
+ } catch (error) {
1611
+ // A synthetic input boundary uses an invalid-character sentinel after
1612
+ // the required peek character. If a complete candidate already ended
1613
+ // at that boundary but did not parse, the term itself is malformed;
1614
+ // consume it and report syntax_error rather than blaming the sentinel.
1615
+ if (sawCandidate && Number.isInteger(stream.syntheticInputBoundary) &&
1616
+ lastCandidateEnd === stream.syntheticInputBoundary && error?.name === 'PrologError' &&
1617
+ error.formal === 'representation_error(character)') {
1618
+ stream.position = lastCandidateEnd;
1619
+ throw new PrologError('syntax_error(read_term)');
1620
+ }
1621
+ throw error;
1597
1622
  }
1598
1623
 
1599
1624
  // The interactive top level may attach a synchronous reader to the
package/src/lib/lists.pl CHANGED
@@ -111,16 +111,23 @@ same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).
111
111
 
112
112
  nth0(N, List, Elem) :- nth0(N, List, Elem, _).
113
113
 
114
- nth0(0, [Elem|Rest], Elem, Rest).
115
- nth0(N, [X|Xs], Elem, [X|Rest]) :-
114
+ nth0(N, List, Elem, Rest) :-
115
+ lists__integer_or_variable(N),
116
+ ( var(N) -> lists__nth0(N, List, Elem, Rest)
117
+ ; lists__not_less_than_zero(N),
118
+ lists__nth0(N, List, Elem, Rest)
119
+ ).
120
+
121
+ lists__nth0(0, [Elem|Rest], Elem, Rest).
122
+ lists__nth0(N, [X|Xs], Elem, [X|Rest]) :-
116
123
  var(N),
117
- nth0(N0, Xs, Elem, Rest),
124
+ lists__nth0(N0, Xs, Elem, Rest),
118
125
  N is N0 + 1.
119
- nth0(N, [X|Xs], Elem, [X|Rest]) :-
126
+ lists__nth0(N, [X|Xs], Elem, [X|Rest]) :-
120
127
  nonvar(N),
121
128
  N > 0,
122
129
  N0 is N - 1,
123
- nth0(N0, Xs, Elem, Rest).
130
+ lists__nth0(N0, Xs, Elem, Rest).
124
131
 
125
132
  nth1(N, List, Elem) :- nth1(N, List, Elem, _).
126
133
 
@@ -208,6 +215,9 @@ lists__integer(X) :- var(X), !, 0 is X.
208
215
  % arg/3 performs the ISO integer type check before inspecting its term.
209
216
  lists__integer(X) :- arg(X, type_check, _).
210
217
 
218
+ lists__integer_or_variable(X) :- var(X), !.
219
+ lists__integer_or_variable(X) :- lists__integer(X).
220
+
211
221
  lists__not_less_than_zero(X) :- X >= 0, !.
212
222
  % atom_length/2 reports domain_error(not_less_than_zero) for a negative value.
213
223
  lists__not_less_than_zero(X) :- atom_length('', X).
@@ -1,4 +1,10 @@
1
- /** Predicates proposed by the ISO Prolog Prologue working draft. */
1
+ /** Predicates proposed by the ISO Prolog Prologue working draft.
2
+
3
+ This legacy compatibility module is a facade over the canonical library
4
+ organization shared with Scryer and Trealla. Keeping one implementation
5
+ owner per predicate lets applications combine library(prologue) with the
6
+ specialized libraries without import conflicts.
7
+ */
2
8
 
3
9
  :- module(prologue, [
4
10
  member/2,
@@ -26,168 +32,26 @@
26
32
  countall/2
27
33
  ]).
28
34
 
29
- :- meta_predicate(maplist(1, '?')).
30
- :- meta_predicate(maplist(2, '?', '?')).
31
- :- meta_predicate(maplist(3, '?', '?', '?')).
32
- :- meta_predicate(maplist(4, '?', '?', '?', '?')).
33
- :- meta_predicate(maplist(5, '?', '?', '?', '?', '?')).
34
- :- meta_predicate(maplist(6, '?', '?', '?', '?', '?', '?')).
35
- :- meta_predicate(maplist(7, '?', '?', '?', '?', '?', '?', '?')).
36
- :- meta_predicate(call_nth(0, '?')).
37
- :- meta_predicate(freeze('?', 0)).
38
- :- meta_predicate(foldl(3, '?', '?', '?')).
39
- :- meta_predicate(foldl(4, '?', '?', '?', '?')).
40
- :- meta_predicate(foldl(5, '?', '?', '?', '?', '?')).
41
- :- meta_predicate(countall(0, '?')).
42
-
43
- member(X, [X|_]).
44
- member(X, [_|Xs]) :- member(X, Xs).
45
-
46
- append([], Ys, Ys).
47
- append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).
48
-
49
- length(List, Length) :-
50
- nonvar(Length), !,
51
- prologue__integer(Length),
52
- prologue__not_less_than_zero(Length),
53
- prologue__length_fixed(Length, List).
54
- length(List, Length) :-
55
- prologue__length_generate(List, 0, Length).
56
-
57
- prologue__length_fixed(0, []).
58
- prologue__length_fixed(N, [_|Xs]) :-
59
- N > 0,
60
- Next is N - 1,
61
- prologue__length_fixed(Next, Xs).
62
-
63
- prologue__length_generate([], N, N).
64
- prologue__length_generate([_|Xs], N0, N) :-
65
- N1 is N0 + 1,
66
- prologue__length_generate(Xs, N1, N).
67
-
68
- between(Lower, Upper, X) :-
69
- prologue__integer(Lower),
70
- prologue__integer(Upper),
71
- prologue__integer_or_variable(X),
72
- prologue__between(Lower, Upper, X).
73
-
74
- prologue__between(Lower, Upper, Lower) :- Lower =< Upper.
75
- prologue__between(Lower, Upper, X) :-
76
- Lower < Upper,
77
- Next is Lower + 1,
78
- prologue__between(Next, Upper, X).
79
-
80
- select(X, [X|Xs], Xs).
81
- select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).
82
-
83
- succ(X, S) :-
84
- var(X), !,
85
- ( var(S) -> 0 is S
86
- ; prologue__integer(S),
87
- prologue__not_less_than_zero(S),
88
- S > 0,
89
- X is S - 1
90
- ).
91
- succ(X, S) :-
92
- prologue__integer(X),
93
- prologue__not_less_than_zero(X),
94
- ( var(S) -> S is X + 1
95
- ; prologue__integer(S),
96
- prologue__not_less_than_zero(S),
97
- S =:= X + 1
98
- ).
99
-
100
- maplist(_, []).
101
- maplist(Closure, [X|Xs]) :-
102
- call(Closure, X),
103
- maplist(Closure, Xs).
104
-
105
- maplist(_, [], []).
106
- maplist(Closure, [A|As], [B|Bs]) :-
107
- call(Closure, A, B),
108
- maplist(Closure, As, Bs).
109
-
110
- maplist(_, [], [], []).
111
- maplist(Closure, [A|As], [B|Bs], [C|Cs]) :-
112
- call(Closure, A, B, C),
113
- maplist(Closure, As, Bs, Cs).
114
-
115
- maplist(_, [], [], [], []).
116
- maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds]) :-
117
- call(Closure, A, B, C, D),
118
- maplist(Closure, As, Bs, Cs, Ds).
119
-
120
- maplist(_, [], [], [], [], []).
121
- maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es]) :-
122
- call(Closure, A, B, C, D, E),
123
- maplist(Closure, As, Bs, Cs, Ds, Es).
124
-
125
- maplist(_, [], [], [], [], [], []).
126
- maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs]) :-
127
- call(Closure, A, B, C, D, E, F),
128
- maplist(Closure, As, Bs, Cs, Ds, Es, Fs).
129
-
130
- maplist(_, [], [], [], [], [], [], []).
131
- maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs], [G|Gs]) :-
132
- call(Closure, A, B, C, D, E, F, G),
133
- maplist(Closure, As, Bs, Cs, Ds, Es, Fs, Gs).
134
-
135
- nth0(N, List, Elem) :- nth0(N, List, Elem, _).
136
-
137
- nth0(N, List, Elem, Rest) :-
138
- prologue__integer_or_variable(N),
139
- ( var(N) -> prologue__nth0(N, List, Elem, Rest)
140
- ; prologue__not_less_than_zero(N),
141
- prologue__nth0(N, List, Elem, Rest)
142
- ).
143
-
144
- prologue__nth0(0, [Elem|Rest], Elem, Rest).
145
- prologue__nth0(N, [X|Xs], Elem, [X|Rest]) :-
146
- var(N),
147
- prologue__nth0(N0, Xs, Elem, Rest),
148
- N is N0 + 1.
149
- prologue__nth0(N, [X|Xs], Elem, [X|Rest]) :-
150
- nonvar(N),
151
- N > 0,
152
- N0 is N - 1,
153
- prologue__nth0(N0, Xs, Elem, Rest).
154
-
155
- nth1(N, List, Elem) :- nth1(N, List, Elem, _).
156
-
157
- nth1(N, List, Elem, Rest) :-
158
- N \== 0,
159
- nth0(N, [_|List], Elem, [_|Rest]),
160
- N \== 0.
161
-
162
- call_nth(Goal, Nth) :- eyeprolog__call_nth(Goal, Nth).
163
-
164
- freeze(Var, Goal) :- eyeprolog__freeze(Var, Goal).
165
-
166
- foldl(_, [], Acc, Acc).
167
- foldl(Closure, [A|As], Acc0, Acc) :-
168
- call(Closure, A, Acc0, Acc1),
169
- foldl(Closure, As, Acc1, Acc).
170
-
171
- foldl(_, [], [], Acc, Acc).
172
- foldl(Closure, [A|As], [B|Bs], Acc0, Acc) :-
173
- call(Closure, A, B, Acc0, Acc1),
174
- foldl(Closure, As, Bs, Acc1, Acc).
175
-
176
- foldl(_, [], [], [], Acc, Acc).
177
- foldl(Closure, [A|As], [B|Bs], [C|Cs], Acc0, Acc) :-
178
- call(Closure, A, B, C, Acc0, Acc1),
179
- foldl(Closure, As, Bs, Cs, Acc1, Acc).
180
-
181
- countall(Goal, Count) :- eyeprolog__countall(Goal, Count).
182
-
183
- prologue__integer_or_variable(X) :- var(X), !.
184
- prologue__integer_or_variable(X) :- prologue__integer(X).
185
-
186
- prologue__integer(X) :- integer(X), !.
187
- prologue__integer(X) :- var(X), !, 0 is X.
188
- % arg/3 performs the required integer type check before inspecting its term.
189
- prologue__integer(X) :- arg(X, type_check, _).
190
-
191
- prologue__not_less_than_zero(X) :- X >= 0, !.
192
- % atom_length/2 reports domain_error(not_less_than_zero) for a negative value.
193
- prologue__not_less_than_zero(X) :- atom_length('', X).
35
+ :- use_module(library(lists), [
36
+ member/2,
37
+ append/3,
38
+ length/2,
39
+ select/3,
40
+ maplist/2,
41
+ maplist/3,
42
+ maplist/4,
43
+ maplist/5,
44
+ maplist/6,
45
+ maplist/7,
46
+ maplist/8,
47
+ nth0/3,
48
+ nth0/4,
49
+ nth1/3,
50
+ nth1/4,
51
+ foldl/4,
52
+ foldl/5,
53
+ foldl/6
54
+ ]).
55
+ :- use_module(library(between), [between/3]).
56
+ :- use_module(library(iso_ext), [succ/2, call_nth/2, countall/2]).
57
+ :- use_module(library(freeze), [freeze/2]).
package/src/program.js CHANGED
@@ -180,12 +180,18 @@ export class Program {
180
180
  for (let i = 0; i < head.arity; i++) indexOne(group.argIndexes[i], head.args[i], clause, group.clauses, clausePosition);
181
181
  }
182
182
  findGroup(name, arity, module = 'user') {
183
- const direct = this.groups.get(modulePredicateKey(module, name, arity));
184
- if (direct) return direct;
185
- const importedModule = this.moduleImports.get(module)?.get(`${name}/${arity}`);
186
- return importedModule == null
187
- ? null
188
- : this.groups.get(modulePredicateKey(importedModule, name, arity)) ?? null;
183
+ const indicator = `${name}/${arity}`;
184
+ const visited = new Set();
185
+ let current = module;
186
+ while (!visited.has(current)) {
187
+ visited.add(current);
188
+ const direct = this.groups.get(modulePredicateKey(current, name, arity));
189
+ if (direct) return direct;
190
+ const importedModule = this.moduleImports.get(current)?.get(indicator);
191
+ if (importedModule == null) return null;
192
+ current = importedModule;
193
+ }
194
+ return null;
189
195
  }
190
196
  defineModule(name, exports, filename = '<input>') {
191
197
  const indicators = new Map(exports.map((indicator) => [`${indicator.name}/${indicator.arity}`, indicator]));
@@ -202,10 +208,16 @@ export class Program {
202
208
  throw new PrologError('existence_error(procedure)', compound('/', [atom(indicator.name), numberTerm(indicator.arity)]));
203
209
  }
204
210
  const previous = imports.get(key);
205
- if (previous != null && previous !== source) {
211
+ const resolved = this.findGroup(indicator.name, indicator.arity, source);
212
+ const canonicalSource = resolved?.module ?? source;
213
+ const previousResolved = previous == null
214
+ ? null
215
+ : this.findGroup(indicator.name, indicator.arity, previous);
216
+ const canonicalPrevious = previousResolved?.module ?? previous;
217
+ if (previous != null && canonicalPrevious !== canonicalSource) {
206
218
  throw new PrologError('permission_error(import, procedure)', compound('/', [atom(indicator.name), numberTerm(indicator.arity)]));
207
219
  }
208
- imports.set(key, source);
220
+ imports.set(key, canonicalSource);
209
221
  }
210
222
  this.moduleImports.set(target, imports);
211
223
  }