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 +34 -2
- package/examples/book/chapter-06/03-square.pl +0 -1
- package/examples/fast-fourier-transform.pl +2 -0
- package/examples/output/fast-fourier-transform.pl +1 -1
- package/examples/sudoku.pl +4 -4
- package/index.d.ts +8 -0
- package/package.json +2 -1
- package/src/cli.js +26 -1
- package/src/index.js +9 -1
- package/src/iso.js +0 -9
- package/src/lib/lists.pl +132 -15
- package/src/program.js +233 -1
- package/src/standard-library.js +60 -5
- package/test/run-interop.mjs +77 -0
- package/test/run-regression.mjs +212 -104
- package/the-art-of-eyeprolog.md +48 -11
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
|
|
127
|
-
profile. **
|
|
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 +1 @@
|
|
|
1
|
-
fft([0, 1, 2, 3, 4, 5, 6, 7], [n(
|
|
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))]).
|
package/examples/sudoku.pl
CHANGED
|
@@ -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
|
-
|
|
113
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
|
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
|
-
%
|
|
30
|
-
%
|
|
31
|
-
%
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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,
|
|
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
|
-
|
|
59
|
-
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).
|
|
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
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
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).
|