eyeprolog 1.3.95 → 1.3.97
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/examples/book/README.md +7 -6
- package/examples/book/chapter-39/01-program.pl +4 -0
- package/examples/book/chapter-39/{01-answer.pl → 02-answer.pl} +1 -1
- package/package.json +1 -1
- package/src/lib/freeze.pl +14 -4
- package/test/run-regression.mjs +46 -0
- package/the-art-of-eyeprolog.md +14 -3
- /package/examples/book/chapter-39/{02-answer-2.pl → 03-answer-2.pl} +0 -0
- /package/examples/book/chapter-39/{03-answer-3.pl → 04-answer-3.pl} +0 -0
- /package/examples/book/chapter-39/{04-cost.pl → 05-cost.pl} +0 -0
- /package/examples/book/chapter-39/{05-message.pl → 06-message.pl} +0 -0
- /package/examples/book/chapter-39/{06-task.pl → 07-task.pl} +0 -0
package/examples/book/README.md
CHANGED
|
@@ -238,12 +238,13 @@ npm run generate
|
|
|
238
238
|
|
|
239
239
|
## Chapter 39: Built-in predicates by programming role
|
|
240
240
|
|
|
241
|
-
- [01-
|
|
242
|
-
- [02-answer
|
|
243
|
-
- [03-answer-
|
|
244
|
-
- [04-
|
|
245
|
-
- [05-
|
|
246
|
-
- [06-
|
|
241
|
+
- [01-program.pl](chapter-39/01-program.pl) — The EyeProlog library
|
|
242
|
+
- [02-answer.pl](chapter-39/02-answer.pl)
|
|
243
|
+
- [03-answer-2.pl](chapter-39/03-answer-2.pl)
|
|
244
|
+
- [04-answer-3.pl](chapter-39/04-answer-3.pl)
|
|
245
|
+
- [05-cost.pl](chapter-39/05-cost.pl)
|
|
246
|
+
- [06-message.pl](chapter-39/06-message.pl)
|
|
247
|
+
- [07-task.pl](chapter-39/07-task.pl)
|
|
247
248
|
|
|
248
249
|
## Chapter 40: Running EyeProlog: command line and corpus
|
|
249
250
|
|
package/package.json
CHANGED
package/src/lib/freeze.pl
CHANGED
|
@@ -10,19 +10,29 @@ verify_attributes(Var, Other, Goals) :-
|
|
|
10
10
|
get_atts(Var, frozen(FrozenA)), !,
|
|
11
11
|
( var(Other) ->
|
|
12
12
|
( get_atts(Other, frozen(FrozenB)) ->
|
|
13
|
-
|
|
13
|
+
append_frozen(FrozenB, FrozenA, Frozen),
|
|
14
|
+
put_atts(Other, frozen(Frozen))
|
|
14
15
|
; put_atts(Other, frozen(FrozenA))
|
|
15
16
|
),
|
|
16
17
|
Goals = []
|
|
17
|
-
; Goals =
|
|
18
|
+
; Goals = FrozenA
|
|
18
19
|
).
|
|
19
20
|
verify_attributes(_, _, []).
|
|
20
21
|
|
|
21
22
|
freeze(X, Goal) :-
|
|
22
|
-
put_atts(Fresh, frozen(Goal)),
|
|
23
|
+
put_atts(Fresh, frozen([Goal])),
|
|
23
24
|
Fresh = X.
|
|
24
25
|
|
|
25
26
|
attribute_goals(Var) -->
|
|
26
27
|
{ get_atts(Var, frozen(Goals)),
|
|
27
28
|
put_atts(Var, -frozen(_)) },
|
|
28
|
-
|
|
29
|
+
frozen_attribute_goals(Goals, Var).
|
|
30
|
+
|
|
31
|
+
frozen_attribute_goals([], _) --> [].
|
|
32
|
+
frozen_attribute_goals([Goal|Goals], Var) -->
|
|
33
|
+
[freeze:freeze(Var, Goal)],
|
|
34
|
+
frozen_attribute_goals(Goals, Var).
|
|
35
|
+
|
|
36
|
+
append_frozen([], Tail, Tail).
|
|
37
|
+
append_frozen([Goal|Goals], Tail, [Goal|Merged]) :-
|
|
38
|
+
append_frozen(Goals, Tail, Merged).
|
package/test/run-regression.mjs
CHANGED
|
@@ -400,6 +400,20 @@ function regressionCases() {
|
|
|
400
400
|
'dif/2 residuals are minimal without auxiliary terms');
|
|
401
401
|
assertEqual(residuals.stderr, '', 'dif/2 normalization display stderr');
|
|
402
402
|
|
|
403
|
+
const perfection = runCli([], {
|
|
404
|
+
input:
|
|
405
|
+
'dif(f(X,A),f(Y,B)), ( true ; A = B ).\n' +
|
|
406
|
+
';\n' +
|
|
407
|
+
'halt.\n',
|
|
408
|
+
});
|
|
409
|
+
assertEqual(perfection.status, 0, 'dif/2 branch-local projection status');
|
|
410
|
+
assertEqual(perfection.stdout,
|
|
411
|
+
'?- dif(f(X, A), f(Y, B))\n' +
|
|
412
|
+
'; A = B, dif(X, Y).\n' +
|
|
413
|
+
'?- ',
|
|
414
|
+
'dif/2 residual projection is re-evaluated after branch-local bindings');
|
|
415
|
+
assertEqual(perfection.stderr, '', 'dif/2 branch-local projection stderr');
|
|
416
|
+
|
|
403
417
|
const pendingDifCount = (text) => {
|
|
404
418
|
const solver = new Solver(Program.parse(''), { registry: getEyePrologRegistry() });
|
|
405
419
|
const solutions = solver.solve([parseGoalText(text)], new Env(), 0);
|
|
@@ -2064,6 +2078,38 @@ c4 ?- call((!;1)).
|
|
|
2064
2078
|
assertEqual(result.stdout, 'quads: 1 run, 1 passed, 0 failed.\n', 'quad report');
|
|
2065
2079
|
},
|
|
2066
2080
|
},
|
|
2081
|
+
{
|
|
2082
|
+
name: 'Prologue freeze keeps multiple delayed goals in separate cut scopes (issue #84)',
|
|
2083
|
+
run: () => {
|
|
2084
|
+
const result = publicApi.runQuads(`:- use_module(library(prologue)).
|
|
2085
|
+
39
|
|
2086
|
+
?- freeze(X,(Y=1;Y=2)), freeze(X,!), X = c ; X=end.
|
|
2087
|
+
X = c, Y = 1
|
|
2088
|
+
; X = end, unexpected.
|
|
2089
|
+
X = c, Y = 1
|
|
2090
|
+
; X = c, Y = 2
|
|
2091
|
+
; X = end.
|
|
2092
|
+
`);
|
|
2093
|
+
assertEqual(result.total, 2, 'quad total');
|
|
2094
|
+
assertEqual(result.passed, 2, 'quad passed');
|
|
2095
|
+
assertEqual(result.failed, 0, 'quad failed');
|
|
2096
|
+
assertEqual(result.stdout, 'quads: 2 run, 2 passed, 0 failed.\n', 'quad report');
|
|
2097
|
+
|
|
2098
|
+
const residuals = runCli([], {
|
|
2099
|
+
input:
|
|
2100
|
+
'use_module(library(freeze)).\n' +
|
|
2101
|
+
'freeze(X,(Y=1;Y=2)), freeze(X,!).\n' +
|
|
2102
|
+
'halt.\n',
|
|
2103
|
+
});
|
|
2104
|
+
assertEqual(residuals.status, 0, 'freeze residual display status');
|
|
2105
|
+
assertEqual(residuals.stdout,
|
|
2106
|
+
'?- true.\n' +
|
|
2107
|
+
'?- freeze:freeze(X, (Y=1;Y=2)), freeze:freeze(X, !).\n' +
|
|
2108
|
+
'?- ',
|
|
2109
|
+
'multiple freeze/2 residuals stay separate');
|
|
2110
|
+
assertEqual(residuals.stderr, '', 'freeze residual display stderr');
|
|
2111
|
+
},
|
|
2112
|
+
},
|
|
2067
2113
|
{
|
|
2068
2114
|
name: 'runQuads covers the remaining finite Prologue examples and arities',
|
|
2069
2115
|
run: () => {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6286,14 +6286,25 @@ kept in the logical environment, so bindings and backtracking remain isolated
|
|
|
6286
6286
|
between solution branches. When a suspension wakes, its goal is meta-invoked
|
|
6287
6287
|
with its own cut scope: a `!` inside the delayed goal may commit choices made by
|
|
6288
6288
|
that invocation, but it cannot prune alternatives that were created before the
|
|
6289
|
-
`freeze/2` call.
|
|
6290
|
-
|
|
6289
|
+
`freeze/2` call. Multiple suspensions on the same variable also remain distinct
|
|
6290
|
+
meta-invocations rather than being collapsed into one conjunction, so a cut in
|
|
6291
|
+
one frozen goal cannot prune alternatives produced by another frozen goal. Thus
|
|
6292
|
+
`call(((Y=1;Y=2),freeze(X,!),X=c));Y=3` retains the three answers `Y=1`, `Y=2`,
|
|
6293
|
+
and `Y=3`.
|
|
6291
6294
|
|
|
6292
6295
|
`dif(?Left,?Right)` posts a delayed finite-tree disequality when its arguments
|
|
6293
6296
|
can still unify. Its residual store is normalized by logical implication:
|
|
6294
6297
|
symmetric or equivalent constraints share one residual, and a stronger
|
|
6295
6298
|
constraint removes weaker ones regardless of insertion order. Independent
|
|
6296
|
-
disequalities remain separate.
|
|
6299
|
+
disequalities remain separate. Residual projection is re-evaluated in each
|
|
6300
|
+
solution environment, so a compound disequality is kept intact until later
|
|
6301
|
+
bindings make one aligned subterm pair sufficient. For example:
|
|
6302
|
+
|
|
6303
|
+
```eyeprolog
|
|
6304
|
+
?- dif(f(X,A),f(Y,B)), ( true ; A = B ).
|
|
6305
|
+
dif(f(X, A), f(Y, B))
|
|
6306
|
+
; A = B, dif(X, Y).
|
|
6307
|
+
```
|
|
6297
6308
|
|
|
6298
6309
|
<!-- eyeprolog-library-catalog:start -->
|
|
6299
6310
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|