eyeprolog 1.2.44 → 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 CHANGED
@@ -123,8 +123,8 @@ noun --> [world] | [prolog].
123
123
  %% goal: phrase(sentence, Words)
124
124
  ```
125
125
 
126
- EyeProlog also adds 99 public library predicate indicators to its 129-entry ISO
127
- profile. **60 are implemented entirely as ordinary Prolog clauses** in focused
126
+ EyeProlog also adds 102 public library predicate indicators to its 129-entry ISO
127
+ profile. **63 are implemented entirely as ordinary Prolog clauses** in focused
128
128
  modules under `src/lib/`; the control predicates and finite-domain
129
129
  `library(clpz)` kernel use backtrackable host support.
130
130
  They are ISO/IEC 13211-2 modules loaded explicitly by purpose, such as
@@ -133,6 +133,38 @@ Portable text
133
133
  predicates use ISO atoms or character lists. The old catch-all
134
134
  `library(eyeprolog)` module is no longer needed.
135
135
 
136
+ ## Trealla and Scryer interoperability
137
+
138
+ EyeProlog keeps a conservative source-level interoperability profile separate
139
+ from the larger EyeProlog library surface. `library(lists)` follows the common
140
+ Trealla/Scryer organization for predicates such as `member/2`, `memberchk/2`,
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, ...`.
145
+
146
+ Outside `--iso-strict`, an otherwise undefined unqualified call may autoload a
147
+ predicate only when the interop profile has one canonical EyeProlog provider.
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.
152
+
153
+ Use `-w` / `--warnings` to diagnose dependencies outside the interop profile,
154
+ or `--portable` to make such diagnostics fail the run. This catches both
155
+ implementation-specific library names and EyeProlog-only predicates such as
156
+ `set_nth0/4` even when they live in an otherwise common module.
157
+
158
+ Cross-engine smoke tests live in `test/run-interop.mjs`. With Trealla (`tpl`)
159
+ and Scryer (`scryer-prolog`) installed, run:
160
+
161
+ ```sh
162
+ npm run test:interop
163
+ ```
164
+
165
+ The GitHub interoperability workflow builds both implementations and runs the
166
+ same portable Sudoku source under EyeProlog, Trealla, and Scryer.
167
+
136
168
  ## Development
137
169
 
138
170
  ```sh
@@ -1,5 +1,4 @@
1
1
  % From The Art of EyeProlog, Chapter 6.
2
- :- use_module(library(prologue), [between/3]).
3
2
  :- use_module(library(lists)).
4
3
 
5
4
  square(N, Square) :-
@@ -1,3 +1,5 @@
1
+ :- use_module(library(lists), [memberchk/2]).
2
+
1
3
  % Fast Fourier Transform
2
4
  % Code from the book "Clause and Effect" Chapter 10
3
5
 
@@ -1 +1 @@
1
- fft([0, 1, 2, 3, 4, 5, 6, 7], [n(232, op(+, 216, 231)), n(231, op(*, 217, 230)), n(230, op(+, 222, 229)), n(229, op(*, 223, 228)), n(228, op(+, 224, 227)), n(227, op(*, 225, 226)), n(226, a(7)), n(225, w ^ 4), n(224, a(3)), n(223, w ^ 6), n(222, op(+, 218, 221)), n(221, op(*, 219, 220)), n(220, a(5)), n(219, w ^ 4), n(218, a(1)), n(217, w ^ 7), n(216, op(+, 208, 215)), n(215, op(*, 209, 214)), n(214, op(+, 210, 213)), n(213, op(*, 211, 212)), n(212, a(6)), n(211, w ^ 4), n(210, a(2)), n(209, w ^ 6), n(208, op(+, 204, 207)), n(207, op(*, 205, 206)), n(206, a(4)), n(205, w ^ 4), n(204, a(0)), n(203, op(+, 187, 202)), n(202, op(*, 188, 201)), n(201, op(+, 193, 200)), n(200, op(*, 194, 199)), n(199, op(+, 195, 198)), n(198, op(*, 196, 197)), n(197, a(7)), n(196, w ^ 0), n(195, a(3)), n(194, w ^ 4), n(193, op(+, 189, 192)), n(192, op(*, 190, 191)), n(191, a(5)), n(190, w ^ 0), n(189, a(1)), n(188, w ^ 6), n(187, op(+, 179, 186)), n(186, op(*, 180, 185)), n(185, op(+, 181, 184)), n(184, op(*, 182, 183)), n(183, a(6)), n(182, w ^ 0), n(181, a(2)), n(180, w ^ 4), n(179, op(+, 175, 178)), n(178, op(*, 176, 177)), n(177, a(4)), n(176, w ^ 0), n(175, a(0)), n(174, op(+, 158, 173)), n(173, op(*, 159, 172)), n(172, op(+, 164, 171)), n(171, op(*, 165, 170)), n(170, op(+, 166, 169)), n(169, op(*, 167, 168)), n(168, a(7)), n(167, w ^ 4), n(166, a(3)), n(165, w ^ 2), n(164, op(+, 160, 163)), n(163, op(*, 161, 162)), n(162, a(5)), n(161, w ^ 4), n(160, a(1)), n(159, w ^ 5), n(158, op(+, 150, 157)), n(157, op(*, 151, 156)), n(156, op(+, 152, 155)), n(155, op(*, 153, 154)), n(154, a(6)), n(153, w ^ 4), n(152, a(2)), n(151, w ^ 2), n(150, op(+, 146, 149)), n(149, op(*, 147, 148)), n(148, a(4)), n(147, w ^ 4), n(146, a(0)), n(145, op(+, 129, 144)), n(144, op(*, 130, 143)), n(143, op(+, 135, 142)), n(142, op(*, 136, 141)), n(141, op(+, 137, 140)), n(140, op(*, 138, 139)), n(139, a(7)), n(138, w ^ 0), n(137, a(3)), n(136, w ^ 0), n(135, op(+, 131, 134)), n(134, op(*, 132, 133)), n(133, a(5)), n(132, w ^ 0), n(131, a(1)), n(130, w ^ 4), n(129, op(+, 121, 128)), n(128, op(*, 122, 127)), n(127, op(+, 123, 126)), n(126, op(*, 124, 125)), n(125, a(6)), n(124, w ^ 0), n(123, a(2)), n(122, w ^ 0), n(121, op(+, 117, 120)), n(120, op(*, 118, 119)), n(119, a(4)), n(118, w ^ 0), n(117, a(0)), n(116, op(+, 100, 115)), n(115, op(*, 101, 114)), n(114, op(+, 106, 113)), n(113, op(*, 107, 112)), n(112, op(+, 108, 111)), n(111, op(*, 109, 110)), n(110, a(7)), n(109, w ^ 4), n(108, a(3)), n(107, w ^ 6), n(106, op(+, 102, 105)), n(105, op(*, 103, 104)), n(104, a(5)), n(103, w ^ 4), n(102, a(1)), n(101, w ^ 3), n(100, op(+, 92, 99)), n(99, op(*, 93, 98)), n(98, op(+, 94, 97)), n(97, op(*, 95, 96)), n(96, a(6)), n(95, w ^ 4), n(94, a(2)), n(93, w ^ 6), n(92, op(+, 88, 91)), n(91, op(*, 89, 90)), n(90, a(4)), n(89, w ^ 4), n(88, a(0)), n(87, op(+, 71, 86)), n(86, op(*, 72, 85)), n(85, op(+, 77, 84)), n(84, op(*, 78, 83)), n(83, op(+, 79, 82)), n(82, op(*, 80, 81)), n(81, a(7)), n(80, w ^ 0), n(79, a(3)), n(78, w ^ 4), n(77, op(+, 73, 76)), n(76, op(*, 74, 75)), n(75, a(5)), n(74, w ^ 0), n(73, a(1)), n(72, w ^ 2), n(71, op(+, 63, 70)), n(70, op(*, 64, 69)), n(69, op(+, 65, 68)), n(68, op(*, 66, 67)), n(67, a(6)), n(66, w ^ 0), n(65, a(2)), n(64, w ^ 4), n(63, op(+, 59, 62)), n(62, op(*, 60, 61)), n(61, a(4)), n(60, w ^ 0), n(59, a(0)), n(58, op(+, 42, 57)), n(57, op(*, 43, 56)), n(56, op(+, 48, 55)), n(55, op(*, 49, 54)), n(54, op(+, 50, 53)), n(53, op(*, 51, 52)), n(52, a(7)), n(51, w ^ 4), n(50, a(3)), n(49, w ^ 2), n(48, op(+, 44, 47)), n(47, op(*, 45, 46)), n(46, a(5)), n(45, w ^ 4), n(44, a(1)), n(43, w ^ 1), n(42, op(+, 34, 41)), n(41, op(*, 35, 40)), n(40, op(+, 36, 39)), n(39, op(*, 37, 38)), n(38, a(6)), n(37, w ^ 4), n(36, a(2)), n(35, w ^ 2), n(34, op(+, 30, 33)), n(33, op(*, 31, 32)), n(32, a(4)), n(31, w ^ 4), n(30, a(0)), n(29, op(+, 13, 28)), n(28, op(*, 14, 27)), n(27, op(+, 19, 26)), n(26, op(*, 20, 25)), n(25, op(+, 21, 24)), n(24, op(*, 22, 23)), n(23, a(7)), n(22, w ^ 0), n(21, a(3)), n(20, w ^ 0), n(19, op(+, 15, 18)), n(18, op(*, 16, 17)), n(17, a(5)), n(16, w ^ 0), n(15, a(1)), n(14, w ^ 0), n(13, op(+, 5, 12)), n(12, op(*, 6, 11)), n(11, op(+, 7, 10)), n(10, op(*, 8, 9)), n(9, a(6)), n(8, w ^ 0), n(7, a(2)), n(6, w ^ 0), n(5, op(+, 1, 4)), n(4, op(*, 2, 3)), n(3, a(4)), n(2, w ^ 0), n(1, a(0))]).
1
+ fft([0, 1, 2, 3, 4, 5, 6, 7], [n(64, op(+, 49, 63)), n(63, op(*, 62, 52)), n(62, w ^ 7), n(61, op(+, 42, 60)), n(60, op(*, 47, 44)), n(59, op(+, 31, 58)), n(58, op(*, 57, 38)), n(57, w ^ 5), n(56, op(+, 11, 55)), n(55, op(*, 24, 21)), n(54, op(+, 49, 53)), n(53, op(*, 50, 52)), n(52, op(+, 34, 51)), n(51, op(*, 47, 36)), n(50, w ^ 3), n(49, op(+, 26, 48)), n(48, op(*, 47, 29)), n(47, w ^ 6), n(46, op(+, 42, 45)), n(45, op(*, 27, 44)), n(44, op(+, 15, 43)), n(43, op(*, 24, 19)), n(42, op(+, 5, 41)), n(41, op(*, 24, 9)), n(40, op(+, 31, 39)), n(39, op(*, 32, 38)), n(38, op(+, 34, 37)), n(37, op(*, 27, 36)), n(36, op(+, 16, 35)), n(35, op(*, 24, 17)), n(34, op(+, 12, 33)), n(33, op(*, 24, 13)), n(32, w ^ 1), n(31, op(+, 26, 30)), n(30, op(*, 27, 29)), n(29, op(+, 6, 28)), n(28, op(*, 24, 7)), n(27, w ^ 2), n(26, op(+, 1, 25)), n(25, op(*, 24, 3)), n(24, w ^ 4), n(23, op(+, 11, 22)), n(22, op(*, 2, 21)), n(21, op(+, 15, 20)), n(20, op(*, 2, 19)), n(19, op(+, 16, 18)), n(18, op(*, 2, 17)), n(17, a(7)), n(16, a(3)), n(15, op(+, 12, 14)), n(14, op(*, 2, 13)), n(13, a(5)), n(12, a(1)), n(11, op(+, 5, 10)), n(10, op(*, 2, 9)), n(9, op(+, 6, 8)), n(8, op(*, 2, 7)), n(7, a(6)), n(6, a(2)), n(5, op(+, 1, 4)), n(4, op(*, 2, 3)), n(3, a(4)), n(2, w ^ 0), n(1, a(0))]).
@@ -1,4 +1,3 @@
1
- :- use_module(library(prologue), [between/3]).
2
1
  :- use_module(library(lists)).
3
2
 
4
3
  % A deterministic 9x9 Sudoku solver.
@@ -108,6 +107,7 @@ segment_unused(Cells, StartColumn, Digit) :-
108
107
  Digit \= C.
109
108
 
110
109
  set_cell(Grid, Row, Column, Digit, Result) :-
111
- nth0(Row, Grid, Cells),
112
- set_nth0(Column, Cells, Digit, UpdatedCells),
113
- set_nth0(Row, Grid, UpdatedCells, Result).
110
+ nth0(Row, Grid, Cells, OtherRows),
111
+ nth0(Column, Cells, _Old, OtherCells),
112
+ nth0(Column, UpdatedCells, Digit, OtherCells),
113
+ nth0(Row, Result, UpdatedCells, OtherRows).
package/index.d.ts CHANGED
@@ -21,6 +21,8 @@ export interface EyePrologRunOptions {
21
21
  analyzeNegation?: boolean;
22
22
  /** Restrict parsing and execution to ISO/IEC 13211-1:1995 plus Corrigenda 1-3. */
23
23
  isoStrict?: boolean;
24
+ /** Autoload uniquely mapped predicates from the conservative interop profile. Defaults to true outside strict ISO mode. */
25
+ autoload?: boolean;
24
26
  /** Initial ISO interpretation of double-quoted list notation. Defaults to chars. */
25
27
  doubleQuotes?: 'chars' | 'codes' | 'atom';
26
28
  ioOptions?: {
@@ -248,6 +250,9 @@ export const standardLibrarySources: ReadonlyMap<string, { filename: string; sou
248
250
  export const eyePrologLibraryIndicators: readonly string[];
249
251
  export const eyePrologNativeLibraryIndicators: readonly string[];
250
252
  export const eyePrologPortableLibraryIndicators: readonly string[];
253
+ export const eyePrologInteropAutoload: Readonly<Record<string, string>>;
254
+ export const eyePrologInteropLibraryIndicators: readonly string[];
255
+ export const eyePrologInteropLibraryModules: readonly string[];
251
256
  export class PrologError extends Error {
252
257
  formal: string;
253
258
  culprit: EyePrologTerm | null;
@@ -326,6 +331,9 @@ declare const eyeprolog: {
326
331
  eyePrologLibraryIndicators: typeof eyePrologLibraryIndicators;
327
332
  eyePrologNativeLibraryIndicators: typeof eyePrologNativeLibraryIndicators;
328
333
  eyePrologPortableLibraryIndicators: typeof eyePrologPortableLibraryIndicators;
334
+ eyePrologInteropAutoload: typeof eyePrologInteropAutoload;
335
+ eyePrologInteropLibraryIndicators: typeof eyePrologInteropLibraryIndicators;
336
+ eyePrologInteropLibraryModules: typeof eyePrologInteropLibraryModules;
329
337
  run: typeof run;
330
338
  runQuads: typeof runQuads;
331
339
  whyProof: typeof whyProof;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.2.44",
6
+ "version": "1.3.1",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
@@ -50,6 +50,7 @@
50
50
  "test:eyeprolog": "node test/run-all.mjs",
51
51
  "test:conformance": "node test/run-conformance.mjs",
52
52
  "test:iso-strict": "node test/run-iso-strict.mjs",
53
+ "test:interop": "node test/run-interop.mjs",
53
54
  "test:wg17": "node test/run-wg17.mjs",
54
55
  "test:examples": "node test/run-examples.mjs",
55
56
  "test:regression": "node test/run-regression.mjs",
package/src/cli.js CHANGED
@@ -28,6 +28,8 @@ export async function main(argv) {
28
28
  quads: false,
29
29
  stats: false,
30
30
  isoStrict: false,
31
+ portable: false,
32
+ autoload: true,
31
33
  version: false,
32
34
  warnings: false,
33
35
  goals: [],
@@ -51,6 +53,10 @@ export async function main(argv) {
51
53
  options.stats = true;
52
54
  } else if (!endOptions && arg === '--iso-strict') {
53
55
  options.isoStrict = true;
56
+ } else if (!endOptions && arg === '--portable') {
57
+ options.portable = true;
58
+ } else if (!endOptions && arg === '--no-autoload') {
59
+ options.autoload = false;
54
60
  } else if (!endOptions && (arg === '--version' || arg === '-v')) {
55
61
  options.version = true;
56
62
  } else if (!endOptions && (arg === '--warnings' || arg === '-w')) {
@@ -146,9 +152,16 @@ export async function main(argv) {
146
152
  let program = engine.Program.parseSources(sourceParts, {
147
153
  sourceMetadata: options.proof || options.isoStrict,
148
154
  isoStrict: options.isoStrict,
155
+ autoload: options.autoload,
156
+ autoloadGoals: options.goals,
149
157
  });
150
158
 
151
- if (options.warnings) printWarnings(program);
159
+ const portabilityFailures = program.interopPortabilityWarnings ?? [];
160
+ if (options.warnings || (options.portable && portabilityFailures.length > 0)) printWarnings(program);
161
+ if (options.portable && portabilityFailures.length > 0) {
162
+ process.exitCode = 1;
163
+ return;
164
+ }
152
165
 
153
166
  if (!options.quads || options.goals.length > 0) await runDefault(engine, program, options);
154
167
  if (options.quads) {
@@ -263,6 +276,8 @@ Options:
263
276
  -s, --stats Print solver and memory statistics to stderr after execution.
264
277
  --iso-strict Use ISO/IEC 13211-1 core + Corrigenda 1-3 only;
265
278
  reject EyeProlog language extensions and disable automatic tabling.
279
+ --portable Enforce the EyeProlog/Trealla/Scryer interop profile.
280
+ --no-autoload Disable conservative interop predicate autoloading.
266
281
  -v, --version Show the package version and exit.
267
282
  -w, --warnings Print non-fatal portability warnings to stderr.
268
283
  -g, --goal goal Solve goal and print its ground answers; may be repeated.
@@ -284,6 +299,16 @@ function readStdin() {
284
299
  }
285
300
 
286
301
  function printWarnings(program) {
302
+ for (const warning of program.interopPortabilityWarnings ?? []) {
303
+ if (warning.kind === 'library') {
304
+ process.stderr.write('eyeprolog warning: non-portable library dependency\n');
305
+ process.stderr.write(` library(${warning.library}) is outside the EyeProlog/Trealla/Scryer interop profile\n`);
306
+ } else if (warning.kind === 'predicate') {
307
+ process.stderr.write('eyeprolog warning: non-portable library predicate\n');
308
+ process.stderr.write(` ${warning.indicator} from library(${warning.library}) is outside the interop profile\n`);
309
+ }
310
+ }
311
+
287
312
  const errors = program.negationStratificationErrors;
288
313
  if (errors.length === 0) return;
289
314
 
package/src/index.js CHANGED
@@ -20,6 +20,9 @@ export {
20
20
  eyePrologLibraryIndicators,
21
21
  eyePrologNativeLibraryIndicators,
22
22
  eyePrologPortableLibraryIndicators,
23
+ eyePrologInteropAutoload,
24
+ eyePrologInteropLibraryIndicators,
25
+ eyePrologInteropLibraryModules,
23
26
  } from './standard-library.js';
24
27
  export { StreamManager } from './io.js';
25
28
  export { runQuads } from './quads.js';
@@ -39,7 +42,12 @@ export function run(source, options = {}) {
39
42
  if (source instanceof Program && requestedStrictIso && source.strictIso !== true) {
40
43
  throw new Error('strict ISO mode requires a Program parsed with isoStrict: true');
41
44
  }
42
- const parseOptions = { ...options, sourceMetadata: includeWhy || requestedStrictIso };
45
+ const requestedGoals = options.goals ?? (options.goal == null ? [] : [options.goal]);
46
+ const parseOptions = {
47
+ ...options,
48
+ sourceMetadata: includeWhy || requestedStrictIso,
49
+ autoloadGoals: requestedGoals,
50
+ };
43
51
  let program = source instanceof Program ? source : Program.parse(source, parseOptions);
44
52
  const strictIso = requestedStrictIso || program.strictIso === true;
45
53
  const runOptions = strictIso
package/src/iso.js CHANGED
@@ -1198,15 +1198,6 @@ function scopeReadTerm(term) {
1198
1198
 
1199
1199
  function parseReadTermText(text, solver) {
1200
1200
  const converted = convertedTermText(text, solver);
1201
- // A standalone number needs no general term parser or operator tables.
1202
- // Reuse the same bounded numeric scanner as number_chars/2 so stream reads
1203
- // and number conversion agree on every accepted numeric token. The stream
1204
- // scanner has already established that the final full stop is a candidate
1205
- // terminator; trim only ISO layout immediately before that terminator.
1206
- const numericText = converted.slice(0, -1).replace(/[\u0009-\u000d\u0020]+$/, '');
1207
- const numericTerm = parseIsoNumber(numericText);
1208
- if (numericTerm != null) return numericTerm;
1209
-
1210
1201
  const operatorState = createParserOperatorState(solver.program.operators.values(), false);
1211
1202
  const clauses = parseClauses(converted, {
1212
1203
  sourceMetadata: false,
package/src/lib/lists.pl CHANGED
@@ -1,15 +1,29 @@
1
1
  /** List relations, following the library(lists) organization used by Scryer. */
2
2
 
3
3
  :- module(lists, [
4
- maplist/3,
5
- append/3,
6
4
  member/2,
5
+ memberchk/2,
7
6
  select/3,
7
+ append/2,
8
+ append/3,
8
9
  last/2,
10
+ same_length/2,
9
11
  nth0/3,
12
+ nth0/4,
10
13
  nth1/3,
14
+ nth1/4,
11
15
  reverse/2,
12
16
  length/2,
17
+ maplist/2,
18
+ maplist/3,
19
+ maplist/4,
20
+ maplist/5,
21
+ maplist/6,
22
+ maplist/7,
23
+ maplist/8,
24
+ foldl/4,
25
+ foldl/5,
26
+ foldl/6,
13
27
  sum_list/2,
14
28
  min_list/2,
15
29
  max_list/2,
@@ -21,42 +35,130 @@
21
35
  slice/4
22
36
  ]).
23
37
 
38
+ :- meta_predicate(maplist(1, '?')).
24
39
  :- meta_predicate(maplist(2, '?', '?')).
40
+ :- meta_predicate(maplist(3, '?', '?', '?')).
41
+ :- meta_predicate(maplist(4, '?', '?', '?', '?')).
42
+ :- meta_predicate(maplist(5, '?', '?', '?', '?', '?')).
43
+ :- meta_predicate(maplist(6, '?', '?', '?', '?', '?', '?')).
44
+ :- meta_predicate(maplist(7, '?', '?', '?', '?', '?', '?', '?')).
45
+ :- meta_predicate(foldl(3, '?', '?', '?')).
46
+ :- meta_predicate(foldl(4, '?', '?', '?', '?')).
47
+ :- meta_predicate(foldl(5, '?', '?', '?', '?', '?')).
25
48
  :- meta_predicate(countall(0, '?')).
26
49
 
27
50
  % Common pure-Prolog library predicates for EyeProlog.
28
51
  %
29
- % Load this module explicitly with use_module(library(lists)). The module
30
- % boundary keeps these widespread names separate from same-named predicates in
31
- % other modules.
52
+ % The common Trealla/Scryer-facing surface can be imported explicitly with
53
+ % use_module(library(lists)); EyeProlog may also autoload those common
54
+ % indicators when an otherwise undefined unqualified call is encountered.
55
+ % EyeProlog-specific helpers remain explicit and are diagnosed by --warnings.
56
+
57
+ maplist(_, []).
58
+ maplist(Closure, [A|As]) :-
59
+ call(Closure, A),
60
+ maplist(Closure, As).
32
61
 
33
62
  maplist(_, [], []).
34
63
  maplist(Closure, [A|As], [B|Bs]) :-
35
64
  call(Closure, A, B),
36
65
  maplist(Closure, As, Bs).
37
66
 
67
+ maplist(_, [], [], []).
68
+ maplist(Closure, [A|As], [B|Bs], [C|Cs]) :-
69
+ call(Closure, A, B, C),
70
+ maplist(Closure, As, Bs, Cs).
71
+
72
+ maplist(_, [], [], [], []).
73
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds]) :-
74
+ call(Closure, A, B, C, D),
75
+ maplist(Closure, As, Bs, Cs, Ds).
76
+
77
+ maplist(_, [], [], [], [], []).
78
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es]) :-
79
+ call(Closure, A, B, C, D, E),
80
+ maplist(Closure, As, Bs, Cs, Ds, Es).
81
+
82
+ maplist(_, [], [], [], [], [], []).
83
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs]) :-
84
+ call(Closure, A, B, C, D, E, F),
85
+ maplist(Closure, As, Bs, Cs, Ds, Es, Fs).
86
+
87
+ maplist(_, [], [], [], [], [], [], []).
88
+ maplist(Closure, [A|As], [B|Bs], [C|Cs], [D|Ds], [E|Es], [F|Fs], [G|Gs]) :-
89
+ call(Closure, A, B, C, D, E, F, G),
90
+ maplist(Closure, As, Bs, Cs, Ds, Es, Fs, Gs).
91
+
92
+ append([], []).
93
+ append([Xs|Xss], Ys) :-
94
+ append(Xs, Rest, Ys),
95
+ append(Xss, Rest).
96
+
38
97
  append([], Ys, Ys).
39
98
  append([X|Xs], Ys, [X|Zs]) :- append(Xs, Ys, Zs).
40
99
 
41
100
  member(X, [X|_]).
42
101
  member(X, [_|Xs]) :- member(X, Xs).
43
102
 
103
+ memberchk(X, Xs) :- member(X, Xs), !.
104
+
44
105
  select(X, [X|Xs], Xs).
45
106
  select(X, [Y|Ys], [Y|Zs]) :- select(X, Ys, Zs).
46
107
 
47
108
  last([X], X).
48
109
  last([_|Xs], X) :- last(Xs, X).
49
110
 
50
- nth0(0, [X|_], X).
51
- nth0(N, [_|Xs], X) :- var(N), nth0(N0, Xs, X), N is N0 + 1.
52
- nth0(N, [_|Xs], X) :- nonvar(N), N > 0, N1 is N - 1, nth0(N1, Xs, X).
111
+ same_length([], []).
112
+ same_length([_|Xs], [_|Ys]) :- same_length(Xs, Ys).
113
+
114
+ nth0(N, List, Elem) :- nth0(N, List, Elem, _).
115
+
116
+ nth0(0, [Elem|Rest], Elem, Rest).
117
+ nth0(N, [X|Xs], Elem, [X|Rest]) :-
118
+ var(N),
119
+ nth0(N0, Xs, Elem, Rest),
120
+ N is N0 + 1.
121
+ nth0(N, [X|Xs], Elem, [X|Rest]) :-
122
+ nonvar(N),
123
+ N > 0,
124
+ N0 is N - 1,
125
+ nth0(N0, Xs, Elem, Rest).
126
+
127
+ nth1(N, List, Elem) :- nth1(N, List, Elem, _).
53
128
 
54
- nth1(N, List, X) :- nth0(N0, List, X), N is N0 + 1.
129
+ nth1(N, List, Elem, Rest) :-
130
+ N \== 0,
131
+ nth0(N, [_|List], Elem, [_|Rest]),
132
+ N \== 0.
55
133
 
56
134
  reverse(List, Reversed) :- lists__reverse(List, [], Reversed).
57
135
 
58
- length(List, Length) :- nonvar(List), lists__length_count(List, 0, Length).
59
- length(List, Length) :- var(List), integer(Length), Length >= 0, lists__length_make(Length, List).
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).
147
+
148
+ foldl(_, [], Acc, Acc).
149
+ foldl(Closure, [A|As], Acc0, Acc) :-
150
+ call(Closure, A, Acc0, Acc1),
151
+ foldl(Closure, As, Acc1, Acc).
152
+
153
+ foldl(_, [], [], Acc, Acc).
154
+ foldl(Closure, [A|As], [B|Bs], Acc0, Acc) :-
155
+ call(Closure, A, B, Acc0, Acc1),
156
+ foldl(Closure, As, Bs, Acc1, Acc).
157
+
158
+ foldl(_, [], [], [], Acc, Acc).
159
+ foldl(Closure, [A|As], [B|Bs], [C|Cs], Acc0, Acc) :-
160
+ call(Closure, A, B, C, Acc0, Acc1),
161
+ foldl(Closure, As, Bs, Cs, Acc1, Acc).
60
162
 
61
163
  sum_list(List, Sum) :- lists__sum_list(List, 0, Sum).
62
164
 
@@ -93,10 +195,25 @@ slice(Start, Count, List, Slice) :-
93
195
  lists__reverse([], Acc, Acc).
94
196
  lists__reverse([X|Xs], Acc, Out) :- lists__reverse(Xs, [X|Acc], Out).
95
197
 
96
- lists__length_count([], N, N).
97
- lists__length_count([_|Xs], N0, N) :- N1 is N0 + 1, lists__length_count(Xs, N1, N).
98
- lists__length_make(0, []).
99
- lists__length_make(N, [_|Xs]) :- N > 0, N1 is N - 1, lists__length_make(N1, Xs).
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).
100
217
 
101
218
  lists__sum_list([], Sum, Sum).
102
219
  lists__sum_list([X|Xs], Acc, Sum) :- Next is Acc + X, lists__sum_list(Xs, Next, Sum).