eyeprolog 1.3.7 → 1.3.8
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 +23 -4
- package/package.json +1 -1
- package/src/lib/lambda.pl +116 -0
- package/src/standard-library.js +5 -1
- package/test/run-regression.mjs +65 -3
- package/the-art-of-eyeprolog.md +40 -6
package/README.md
CHANGED
|
@@ -189,12 +189,13 @@ noun --> [world] | [prolog].
|
|
|
189
189
|
%% goal: phrase(sentence, Words)
|
|
190
190
|
```
|
|
191
191
|
|
|
192
|
-
EyeProlog also adds
|
|
193
|
-
profile. **
|
|
194
|
-
modules under `src/lib/`; the control predicates and finite-domain
|
|
192
|
+
EyeProlog also adds 126 public library predicate indicators to its 129-entry ISO
|
|
193
|
+
profile. **87 are implemented entirely as ordinary Prolog clauses** in focused
|
|
194
|
+
modules under `src/lib/`; the remaining control predicates and finite-domain
|
|
195
195
|
`library(clpz)` kernel use backtrackable host support.
|
|
196
196
|
They are ISO/IEC 13211-2 modules loaded explicitly by purpose, such as
|
|
197
|
-
`library(lists)`, `library(
|
|
197
|
+
`library(lists)`, `library(lambda)`, `library(strings)`, `library(aggregate)`, or
|
|
198
|
+
`library(clpz)`.
|
|
198
199
|
Portable text
|
|
199
200
|
predicates use ISO atoms or character lists. The old catch-all
|
|
200
201
|
`library(eyeprolog)` module is no longer needed.
|
|
@@ -217,6 +218,24 @@ they can be imported together without an accidental import conflict. EyeProlog's
|
|
|
217
218
|
legacy `library(prologue)` remains a compatibility umbrella and should be
|
|
218
219
|
selectively imported when mixed with the aligned modules.
|
|
219
220
|
|
|
221
|
+
`library(lambda)` follows Scryer's higher-order lambda notation, adapted from
|
|
222
|
+
Ulrich Neumerkel's permissively licensed implementation. Importing it installs
|
|
223
|
+
the `+\` operator and enables closures such as `\X^Goal` and
|
|
224
|
+
`Free+\X^Goal`. Parameters are supplied by `call/N`; variables not listed in
|
|
225
|
+
`Free` are copied afresh for each invocation, while explicitly free variables
|
|
226
|
+
remain shared. For example:
|
|
227
|
+
|
|
228
|
+
```prolog
|
|
229
|
+
:- use_module(library(lambda)).
|
|
230
|
+
:- use_module(library(lists)).
|
|
231
|
+
|
|
232
|
+
all_positive(Xs) :- maplist(\X^(X > 0), Xs).
|
|
233
|
+
all_equal(Y, Xs) :- maplist(Y+\X^(X = Y), Xs).
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
The explicit import is intentional: unlike ordinary predicate autoloading, the
|
|
237
|
+
lambda syntax also changes the active operator table.
|
|
238
|
+
|
|
220
239
|
Outside `--iso-strict`, an otherwise undefined unqualified call may autoload a
|
|
221
240
|
predicate only when the interop profile has one canonical EyeProlog provider.
|
|
222
241
|
For example, `member/2` autoloads from `library(lists)`, `call_nth/2` from
|
package/package.json
CHANGED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Author: Ulrich Neumerkel
|
|
3
|
+
E-mail: ulrich@complang.tuwien.ac.at
|
|
4
|
+
Copyright (C): 2009 Ulrich Neumerkel. All rights reserved.
|
|
5
|
+
|
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
|
7
|
+
modification, are permitted provided that the following conditions are
|
|
8
|
+
met:
|
|
9
|
+
|
|
10
|
+
1. Redistributions of source code must retain the above copyright
|
|
11
|
+
notice, this list of conditions and the following disclaimer.
|
|
12
|
+
|
|
13
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
14
|
+
notice, this list of conditions and the following disclaimer in the
|
|
15
|
+
documentation and/or other materials provided with the distribution.
|
|
16
|
+
|
|
17
|
+
THIS SOFTWARE IS PROVIDED BY Ulrich Neumerkel ``AS IS'' AND ANY
|
|
18
|
+
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
19
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
20
|
+
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Ulrich Neumerkel OR
|
|
21
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
22
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
23
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
24
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
25
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
26
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
27
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
28
|
+
|
|
29
|
+
The views and conclusions contained in the software and documentation
|
|
30
|
+
are those of the authors and should not be interpreted as representing
|
|
31
|
+
official policies, either expressed or implied, of Ulrich Neumerkel.
|
|
32
|
+
|
|
33
|
+
Adapted for EyeProlog from Scryer Prolog library(lambda):
|
|
34
|
+
https://github.com/mthom/scryer-prolog/blob/master/src/lib/lambda.pl
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/** Lambda expressions for higher-order programming based on call/N.
|
|
38
|
+
|
|
39
|
+
Supported forms follow Scryer Prolog library(lambda):
|
|
40
|
+
|
|
41
|
+
Free+\X1^X2^...^XN^Goal
|
|
42
|
+
\X1^X2^...^XN^Goal
|
|
43
|
+
|
|
44
|
+
The second form is shorthand for a lambda with no explicitly shared free
|
|
45
|
+
variables. Variables not listed in Free are copied afresh for each call.
|
|
46
|
+
*/
|
|
47
|
+
|
|
48
|
+
:- module(lambda, [
|
|
49
|
+
(^)/3, (^)/4, (^)/5, (^)/6, (^)/7, (^)/8, (^)/9, (^)/10,
|
|
50
|
+
(\)/1, (\)/2, (\)/3, (\)/4, (\)/5, (\)/6, (\)/7, (\)/8,
|
|
51
|
+
(+\)/2, (+\)/3, (+\)/4, (+\)/5, (+\)/6, (+\)/7, (+\)/8, (+\)/9
|
|
52
|
+
]).
|
|
53
|
+
|
|
54
|
+
% Scryer exports this operator from library(lambda). EyeProlog applies module
|
|
55
|
+
% operator directives while loading the library, so importing the module makes
|
|
56
|
+
% the same syntax available to the importing compilation unit and REPL state.
|
|
57
|
+
:- op(201, xfx, +\).
|
|
58
|
+
|
|
59
|
+
:- meta_predicate(^(?, 0, ?)).
|
|
60
|
+
:- meta_predicate(^(?, 1, ?, ?)).
|
|
61
|
+
:- meta_predicate(^(?, 2, ?, ?, ?)).
|
|
62
|
+
:- meta_predicate(^(?, 3, ?, ?, ?, ?)).
|
|
63
|
+
:- meta_predicate(^(?, 4, ?, ?, ?, ?, ?)).
|
|
64
|
+
:- meta_predicate(^(?, 5, ?, ?, ?, ?, ?, ?)).
|
|
65
|
+
:- meta_predicate(^(?, 6, ?, ?, ?, ?, ?, ?, ?)).
|
|
66
|
+
:- meta_predicate(^(?, 7, ?, ?, ?, ?, ?, ?, ?, ?)).
|
|
67
|
+
:- meta_predicate(\(0)).
|
|
68
|
+
:- meta_predicate(\(1, ?)).
|
|
69
|
+
:- meta_predicate(\(2, ?, ?)).
|
|
70
|
+
:- meta_predicate(\(3, ?, ?, ?)).
|
|
71
|
+
:- meta_predicate(\(4, ?, ?, ?, ?)).
|
|
72
|
+
:- meta_predicate(\(5, ?, ?, ?, ?, ?)).
|
|
73
|
+
:- meta_predicate(\(6, ?, ?, ?, ?, ?, ?)).
|
|
74
|
+
:- meta_predicate(\(7, ?, ?, ?, ?, ?, ?, ?)).
|
|
75
|
+
:- meta_predicate(+\(?, 0)).
|
|
76
|
+
:- meta_predicate(+\(?, 1, ?)).
|
|
77
|
+
:- meta_predicate(+\(?, 2, ?, ?)).
|
|
78
|
+
:- meta_predicate(+\(?, 3, ?, ?, ?)).
|
|
79
|
+
:- meta_predicate(+\(?, 4, ?, ?, ?, ?)).
|
|
80
|
+
:- meta_predicate(+\(?, 5, ?, ?, ?, ?, ?)).
|
|
81
|
+
:- meta_predicate(+\(?, 6, ?, ?, ?, ?, ?, ?)).
|
|
82
|
+
:- meta_predicate(+\(?, 7, ?, ?, ?, ?, ?, ?, ?)).
|
|
83
|
+
|
|
84
|
+
^(V1, C0, V1) :- lambda__no_hat_call(C0).
|
|
85
|
+
^(V1, C1, V1, V2) :- call(C1, V2).
|
|
86
|
+
^(V1, C2, V1, V2, V3) :- call(C2, V2, V3).
|
|
87
|
+
^(V1, C3, V1, V2, V3, V4) :- call(C3, V2, V3, V4).
|
|
88
|
+
^(V1, C4, V1, V2, V3, V4, V5) :- call(C4, V2, V3, V4, V5).
|
|
89
|
+
^(V1, C5, V1, V2, V3, V4, V5, V6) :- call(C5, V2, V3, V4, V5, V6).
|
|
90
|
+
^(V1, C6, V1, V2, V3, V4, V5, V6, V7) :- call(C6, V2, V3, V4, V5, V6, V7).
|
|
91
|
+
^(V1, C7, V1, V2, V3, V4, V5, V6, V7, V8) :- call(C7, V2, V3, V4, V5, V6, V7, V8).
|
|
92
|
+
|
|
93
|
+
\(FC0) :- copy_term(FC0, C0), lambda__no_hat_call(C0).
|
|
94
|
+
\(FC1, V1) :- copy_term(FC1, C1), call(C1, V1).
|
|
95
|
+
\(FC2, V1, V2) :- copy_term(FC2, C2), call(C2, V1, V2).
|
|
96
|
+
\(FC3, V1, V2, V3) :- copy_term(FC3, C3), call(C3, V1, V2, V3).
|
|
97
|
+
\(FC4, V1, V2, V3, V4) :- copy_term(FC4, C4), call(C4, V1, V2, V3, V4).
|
|
98
|
+
\(FC5, V1, V2, V3, V4, V5) :- copy_term(FC5, C5), call(C5, V1, V2, V3, V4, V5).
|
|
99
|
+
\(FC6, V1, V2, V3, V4, V5, V6) :- copy_term(FC6, C6), call(C6, V1, V2, V3, V4, V5, V6).
|
|
100
|
+
\(FC7, V1, V2, V3, V4, V5, V6, V7) :- copy_term(FC7, C7), call(C7, V1, V2, V3, V4, V5, V6, V7).
|
|
101
|
+
|
|
102
|
+
+\(GV, FC0) :- copy_term(GV+FC0, GV+C0), lambda__no_hat_call(C0).
|
|
103
|
+
+\(GV, FC1, V1) :- copy_term(GV+FC1, GV+C1), call(C1, V1).
|
|
104
|
+
+\(GV, FC2, V1, V2) :- copy_term(GV+FC2, GV+C2), call(C2, V1, V2).
|
|
105
|
+
+\(GV, FC3, V1, V2, V3) :- copy_term(GV+FC3, GV+C3), call(C3, V1, V2, V3).
|
|
106
|
+
+\(GV, FC4, V1, V2, V3, V4) :- copy_term(GV+FC4, GV+C4), call(C4, V1, V2, V3, V4).
|
|
107
|
+
+\(GV, FC5, V1, V2, V3, V4, V5) :- copy_term(GV+FC5, GV+C5), call(C5, V1, V2, V3, V4, V5).
|
|
108
|
+
+\(GV, FC6, V1, V2, V3, V4, V5, V6) :- copy_term(GV+FC6, GV+C6), call(C6, V1, V2, V3, V4, V5, V6).
|
|
109
|
+
+\(GV, FC7, V1, V2, V3, V4, V5, V6, V7) :- copy_term(GV+FC7, GV+C7), call(C7, V1, V2, V3, V4, V5, V6, V7).
|
|
110
|
+
|
|
111
|
+
lambda__no_hat_call(Goal) :-
|
|
112
|
+
nonvar(Goal),
|
|
113
|
+
Goal = (_^_),
|
|
114
|
+
!,
|
|
115
|
+
throw(error(existence_error(lambda_parameter, Goal), _)).
|
|
116
|
+
lambda__no_hat_call(Goal) :- call(Goal).
|
package/src/standard-library.js
CHANGED
|
@@ -13,6 +13,7 @@ const moduleFiles = Object.freeze({
|
|
|
13
13
|
comparison: 'comparison.pl',
|
|
14
14
|
dates: 'dates.pl',
|
|
15
15
|
iso_ext: 'iso_ext.pl',
|
|
16
|
+
lambda: 'lambda.pl',
|
|
16
17
|
lists: 'lists.pl',
|
|
17
18
|
primes: 'primes.pl',
|
|
18
19
|
prologue: 'prologue.pl',
|
|
@@ -68,6 +69,9 @@ export const eyePrologPortableLibraryIndicators = Object.freeze([
|
|
|
68
69
|
'length/2', 'sum_list/2', 'min_list/2', 'max_list/2', 'list_to_set/2',
|
|
69
70
|
'succ/2', 'foldl/4', 'foldl/5', 'foldl/6',
|
|
70
71
|
'forall/2', 'cfor/3', 'findall/4', 'variant/2', 'uuid/3',
|
|
72
|
+
'^/3', '^/4', '^/5', '^/6', '^/7', '^/8', '^/9', '^/10',
|
|
73
|
+
'\\/1', '\\/2', '\\/3', '\\/4', '\\/5', '\\/6', '\\/7', '\\/8',
|
|
74
|
+
'+\\/2', '+\\/3', '+\\/4', '+\\/5', '+\\/6', '+\\/7', '+\\/8', '+\\/9',
|
|
71
75
|
]);
|
|
72
76
|
export const eyePrologLibraryIndicators = Object.freeze([
|
|
73
77
|
...eyePrologPortableLibraryIndicators,
|
|
@@ -127,7 +131,7 @@ export const eyePrologInteropLibraryIndicators = Object.freeze(
|
|
|
127
131
|
// Libraries whose *name* is part of the current interop profile. A program
|
|
128
132
|
// may freely use_module/1 with these common module names; predicates in those
|
|
129
133
|
// modules outside eyePrologInteropLibraryIndicators are still diagnosed when used.
|
|
130
|
-
export const eyePrologInteropLibraryModules = Object.freeze(['lists', 'iso_ext']);
|
|
134
|
+
export const eyePrologInteropLibraryModules = Object.freeze(['lists', 'iso_ext', 'lambda']);
|
|
131
135
|
|
|
132
136
|
function* tabledNegationBuiltin({ solver, goal, env }) {
|
|
133
137
|
yield* solver.solveTabledNegation(goal.args[0], env);
|
package/test/run-regression.mjs
CHANGED
|
@@ -3307,6 +3307,68 @@ check(A, B, C, D, E, F) :-
|
|
|
3307
3307
|
assertIncludes(result.stdout, 'check("ab", "a", "ab", [a - 1, b - 2], 6, "a").\n', 'stdout');
|
|
3308
3308
|
},
|
|
3309
3309
|
},
|
|
3310
|
+
{
|
|
3311
|
+
name: 'library(lambda) supports Scryer-style maplist lambdas',
|
|
3312
|
+
run: () => {
|
|
3313
|
+
const source = String.raw`:- use_module(library(lambda)).
|
|
3314
|
+
:- use_module(library(lists)).
|
|
3315
|
+
answer :- maplist(\X^(X>3), [4,5,9]).
|
|
3316
|
+
`;
|
|
3317
|
+
const result = run(source, { goal: 'answer' });
|
|
3318
|
+
assertEqual(result.stdout, 'answer.\n', 'stdout');
|
|
3319
|
+
},
|
|
3320
|
+
},
|
|
3321
|
+
{
|
|
3322
|
+
name: 'library(lambda) refreshes local variables on each invocation',
|
|
3323
|
+
run: () => {
|
|
3324
|
+
const source = String.raw`:- use_module(library(lambda)).
|
|
3325
|
+
:- use_module(library(lists)).
|
|
3326
|
+
answer :- maplist(\X^(Y=X), [a,b]).
|
|
3327
|
+
`;
|
|
3328
|
+
const result = run(source, { goal: 'answer' });
|
|
3329
|
+
assertEqual(result.stdout, 'answer.\n', 'fresh local variables');
|
|
3330
|
+
},
|
|
3331
|
+
},
|
|
3332
|
+
{
|
|
3333
|
+
name: 'library(lambda) preserves explicitly free variables with +\\',
|
|
3334
|
+
run: () => {
|
|
3335
|
+
const source = String.raw`:- use_module(library(lambda)).
|
|
3336
|
+
:- use_module(library(lists)).
|
|
3337
|
+
answer(Y) :- maplist(Y+\X^(Y=X), [a,a]).
|
|
3338
|
+
`;
|
|
3339
|
+
const program = Program.parse(source);
|
|
3340
|
+
const imported = [...program.operators.values()].find((operator) => operator.name === '+\\');
|
|
3341
|
+
assertEqual(`${imported?.priority}/${imported?.specifier}`, '201/xfx', '+\\ operator import');
|
|
3342
|
+
const result = run(program, { goal: 'answer(Y)' });
|
|
3343
|
+
assertEqual(result.stdout, 'answer(a).\n', 'free variable sharing');
|
|
3344
|
+
},
|
|
3345
|
+
},
|
|
3346
|
+
{
|
|
3347
|
+
name: 'library(lambda) supports continuations and seven call arguments',
|
|
3348
|
+
run: () => {
|
|
3349
|
+
const source = String.raw`:- use_module(library(lambda)).
|
|
3350
|
+
f(x,y).
|
|
3351
|
+
tuple(a,b,c,d,e,f,g).
|
|
3352
|
+
answer(A,B) :-
|
|
3353
|
+
call(\X^f(X), A, B),
|
|
3354
|
+
call(\X^Y^f(X,Y), A, B),
|
|
3355
|
+
call(\P^Q^R^S^T^U^V^tuple(P,Q,R,S,T,U,V), a,b,c,d,e,f,g).
|
|
3356
|
+
`;
|
|
3357
|
+
const result = run(source, { goal: 'answer(A,B)' });
|
|
3358
|
+
assertEqual(result.stdout, 'answer(x, y).\n', 'continuations');
|
|
3359
|
+
},
|
|
3360
|
+
},
|
|
3361
|
+
{
|
|
3362
|
+
name: 'library(lambda) diagnoses a missing lambda parameter',
|
|
3363
|
+
run: () => {
|
|
3364
|
+
const source = String.raw`:- use_module(library(lambda)).
|
|
3365
|
+
answer(ok) :-
|
|
3366
|
+
catch(call(\X^true), error(existence_error(lambda_parameter,_),_), true).
|
|
3367
|
+
`;
|
|
3368
|
+
const result = run(source, { goal: 'answer(X)' });
|
|
3369
|
+
assertEqual(result.stdout, 'answer(ok).\n', 'lambda parameter error');
|
|
3370
|
+
},
|
|
3371
|
+
},
|
|
3310
3372
|
{
|
|
3311
3373
|
name: 'autoload metadata records canonical interop imports',
|
|
3312
3374
|
run: () => {
|
|
@@ -3733,16 +3795,16 @@ check(A, B, C, D, E, F) :-
|
|
|
3733
3795
|
assertEqual(registry.get('tnot', 1), null, 'tnot/1 is absent from the ISO registry');
|
|
3734
3796
|
assertEqual(Boolean(library.get('tnot', 1)), true, 'tnot/1 is an EyeProlog WFS extension');
|
|
3735
3797
|
assertEqual(registeredNativeEyePrologLibraryNames().length, 40, 'public native EyeProlog builtin count');
|
|
3736
|
-
assertEqual(eyePrologPortableLibraryIndicators.length,
|
|
3798
|
+
assertEqual(eyePrologPortableLibraryIndicators.length, 86, 'portable Prolog library count');
|
|
3737
3799
|
assertEqual(eyePrologInteropLibraryIndicators.length, 27, 'cross-implementation interop profile count');
|
|
3738
|
-
assertEqual(eyePrologInteropLibraryModules.join(','), 'lists,iso_ext', 'common explicit library module profile');
|
|
3800
|
+
assertEqual(eyePrologInteropLibraryModules.join(','), 'lists,iso_ext,lambda', 'common explicit library module profile');
|
|
3739
3801
|
assertEqual(eyePrologInteropAutoload['member/2'], 'lists', 'member/2 canonical autoload');
|
|
3740
3802
|
assertEqual(eyePrologInteropAutoload['between/3'], 'prologue', 'between/3 canonical internal autoload');
|
|
3741
3803
|
assertEqual(eyePrologInteropAutoload['call_nth/2'], 'iso_ext', 'call_nth/2 canonical interop autoload');
|
|
3742
3804
|
assertEqual(eyePrologInteropAutoload['set_nth0/4'] ?? null, null, 'EyeProlog-only set_nth0/4 is not autoloadable');
|
|
3743
3805
|
assertEqual(eyePrologNativeLibraryIndicators.length, 40, 'native host library count');
|
|
3744
3806
|
assertEqual(eyePrologNativeLibraryIndicators.slice(0, 2).join(','), 'call_nth/2,freeze/2', 'control predicates requiring host support');
|
|
3745
|
-
assertEqual(eyePrologLibraryIndicators.length,
|
|
3807
|
+
assertEqual(eyePrologLibraryIndicators.length, 126, 'complete EyeProlog library surface');
|
|
3746
3808
|
assertEqual(registry.get('eyeprolog__call_nth', 2), null, 'private call_nth adapter is absent from ISO registry');
|
|
3747
3809
|
assertEqual(Boolean(library.get('eyeprolog__call_nth', 2)), true, 'private call_nth adapter is registered for EyeProlog');
|
|
3748
3810
|
assertEqual(library.get('eyeprolog__call_nth', 2)?.eyePrologLibrary, true, 'private adapter is marked as library support');
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6039,19 +6039,19 @@ so side effects occur in Prolog execution order.
|
|
|
6039
6039
|
|
|
6040
6040
|
### The EyeProlog library
|
|
6041
6041
|
|
|
6042
|
-
EyeProlog exposes **
|
|
6043
|
-
indicators in its isolated ISO profile. **
|
|
6042
|
+
EyeProlog exposes **126 library predicate indicators** in addition to the 129
|
|
6043
|
+
indicators in its isolated ISO profile. **87 are defined as ordinary Prolog
|
|
6044
6044
|
clauses** in focused modules under `src/lib/`. The remaining 39
|
|
6045
6045
|
are public wrappers around backtrackable host support: Prologue `call_nth/2` and
|
|
6046
6046
|
`freeze/2`, plus the 37-predicate finite-domain `library(clpz)` kernel. The
|
|
6047
|
-
resulting normal EyeProlog language surface is therefore **
|
|
6047
|
+
resulting normal EyeProlog language surface is therefore **255 public predicate
|
|
6048
6048
|
indicators**. Internally, the runtime registry contains the 129 ISO definitions
|
|
6049
6049
|
plus 23 private library adapters; public relations remain module source clauses.
|
|
6050
6050
|
|
|
6051
6051
|
The sources are `src/lib/aggregate.pl`, `src/lib/clpz.pl`, `src/lib/comparison.pl`,
|
|
6052
|
-
`src/lib/dates.pl`, `src/lib/iso_ext.pl`, `src/lib/
|
|
6053
|
-
`src/lib/
|
|
6054
|
-
`src/lib/strings.pl`, and `src/lib/uuid.pl`. Each declares a same-named module
|
|
6052
|
+
`src/lib/dates.pl`, `src/lib/iso_ext.pl`, `src/lib/lambda.pl`,
|
|
6053
|
+
`src/lib/lists.pl`, `src/lib/primes.pl`, `src/lib/prologue.pl`,
|
|
6054
|
+
`src/lib/random.pl`, `src/lib/strings.pl`, and `src/lib/uuid.pl`. Each declares a same-named module
|
|
6055
6055
|
with `module/2`; there is no catch-all `library(eyeprolog)`. A program imports
|
|
6056
6056
|
only the modules it needs, and
|
|
6057
6057
|
`use_module/2` can select an even smaller indicator list. The Prologue
|
|
@@ -6083,6 +6083,7 @@ between solution branches.
|
|
|
6083
6083
|
| `library(comparison)` | `lt/2`, `gt/2`, `le/2`, `ge/2` |
|
|
6084
6084
|
| `library(dates)` | `difference/3` |
|
|
6085
6085
|
| `library(iso_ext)` | `call_nth/2`, `countall/2`, `forall/2`, `succ/2`, `cfor/3`, `findall/4`, `variant/2` |
|
|
6086
|
+
| `library(lambda)` | `^/3`, `^/4`, `^/5`, `^/6`, `^/7`, `^/8`, `^/9`, `^/10`, `\/1`, `\/2`, `\/3`, `\/4`, `\/5`, `\/6`, `\/7`, `\/8`, `+\/2`, `+\/3`, `+\/4`, `+\/5`, `+\/6`, `+\/7`, `+\/8`, `+\/9` |
|
|
6086
6087
|
| `library(lists)` | `member/2`, `memberchk/2`, `select/3`, `append/2`, `append/3`, `last/2`, `same_length/2`, `nth0/3`, `nth0/4`, `nth1/3`, `nth1/4`, `reverse/2`, `length/2`, `maplist/2`, `maplist/3`, `maplist/4`, `maplist/5`, `maplist/6`, `maplist/7`, `maplist/8`, `foldl/4`, `foldl/5`, `foldl/6`, `sum_list/2`, `min_list/2`, `max_list/2`, `list_to_set/2`, `set_nth0/4`, `take/3`, `drop/3`, `slice/4` |
|
|
6087
6088
|
| `library(primes)` | `smallest_divisor_from/3` |
|
|
6088
6089
|
| `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`, `freeze/2`, `foldl/4`, `foldl/5`, `foldl/6`, `countall/2` |
|
|
@@ -6118,6 +6119,39 @@ so a source file may import both without an accidental predicate collision.
|
|
|
6118
6119
|
overlap these modules; use selective imports when legacy code combines it with
|
|
6119
6120
|
the aligned libraries.
|
|
6120
6121
|
|
|
6122
|
+
`library(lambda)` is an explicitly imported Scryer-aligned module for
|
|
6123
|
+
higher-order programming. Its implementation is adapted from Ulrich Neumerkel's
|
|
6124
|
+
`library(lambda)` as distributed by Scryer Prolog, retaining the upstream
|
|
6125
|
+
copyright and redistribution notice. The public syntax is:
|
|
6126
|
+
|
|
6127
|
+
```text
|
|
6128
|
+
\X1^X2^...^XN^Goal
|
|
6129
|
+
Free+\X1^X2^...^XN^Goal
|
|
6130
|
+
```
|
|
6131
|
+
|
|
6132
|
+
The first form has no explicitly shared free variables. Before each invocation
|
|
6133
|
+
EyeProlog copies the closure term, so local variables are fresh on successive
|
|
6134
|
+
`maplist/2-8`, `foldl/4-6`, or direct `call/N` uses. In the second form, the
|
|
6135
|
+
variables contained in `Free` remain shared with the surrounding goal. Importing
|
|
6136
|
+
the library installs `+\` as a priority-201 `xfx` operator; `\` and `^` use
|
|
6137
|
+
their existing ISO operator definitions. Parenthesize lower-priority goal
|
|
6138
|
+
operators after `^`, for example `\X^(X > 3)`.
|
|
6139
|
+
|
|
6140
|
+
A continuation lambda may leave arguments for a later call:
|
|
6141
|
+
|
|
6142
|
+
```text
|
|
6143
|
+
f(x, y).
|
|
6144
|
+
|
|
6145
|
+
answer(A, B) :- call(\X^f(X), A, B).
|
|
6146
|
+
```
|
|
6147
|
+
|
|
6148
|
+
This is equivalent to supplying both arguments directly. A lambda that is
|
|
6149
|
+
called with too few parameters raises `existence_error(lambda_parameter, ...)`,
|
|
6150
|
+
matching the diagnostic intent of the Scryer library. EyeProlog uses its ISO
|
|
6151
|
+
`copy_term/2` implementation for the fresh-copy step; in EyeProlog this gives
|
|
6152
|
+
the natural-copy behavior needed by the library without requiring a separate
|
|
6153
|
+
`copy_term_nat/2` predicate.
|
|
6154
|
+
|
|
6121
6155
|
Normal EyeProlog execution can autoload an otherwise undefined unqualified call
|
|
6122
6156
|
only when the interop table assigns it one canonical provider. Thus `member/2`
|
|
6123
6157
|
autoloads from `library(lists)`, `call_nth/2` from `library(iso_ext)`, and
|