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.
@@ -238,12 +238,13 @@ npm run generate
238
238
 
239
239
  ## Chapter 39: Built-in predicates by programming role
240
240
 
241
- - [01-answer.pl](chapter-39/01-answer.pl) — The EyeProlog library
242
- - [02-answer-2.pl](chapter-39/02-answer-2.pl)
243
- - [03-answer-3.pl](chapter-39/03-answer-3.pl)
244
- - [04-cost.pl](chapter-39/04-cost.pl)
245
- - [05-message.pl](chapter-39/05-message.pl)
246
- - [06-task.pl](chapter-39/06-task.pl)
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
 
@@ -0,0 +1,4 @@
1
+ % From The Art of EyeProlog, Chapter 39 — The EyeProlog library.
2
+ ?- dif(f(X,A),f(Y,B)), ( true ; A = B ).
3
+ dif(f(X, A), f(Y, B))
4
+ ; A = B, dif(X, Y).
@@ -1,4 +1,4 @@
1
- % From The Art of EyeProlog, Chapter 39 — The EyeProlog library.
1
+ % From The Art of EyeProlog, Chapter 39.
2
2
  :- use_module(library(dates)).
3
3
  :- use_module(library(between), [between/3]).
4
4
  :- use_module(library(random)).
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "1.3.95",
6
+ "version": "1.3.97",
7
7
  "description": "EyeProlog turns facts and rules into answers and proofs.",
8
8
  "type": "module",
9
9
  "main": "./index.js",
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
- put_atts(Other, frozen((FrozenB,FrozenA)))
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 = [FrozenA]
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
- [freeze:freeze(Var, Goals)].
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).
@@ -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: () => {
@@ -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. Thus `call(((Y=1;Y=2),freeze(X,!),X=c));Y=3` retains the three
6290
- answers `Y=1`, `Y=2`, and `Y=3`.
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