eyeprolog 1.3.93 → 1.3.94
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/package.json +1 -1
- package/src/solver.js +9 -2
- package/test/run-regression.mjs +16 -0
- package/the-art-of-eyeprolog.md +5 -1
package/package.json
CHANGED
package/src/solver.js
CHANGED
|
@@ -524,14 +524,21 @@ export class Solver {
|
|
|
524
524
|
if (this.solutionsSeen >= this.solutionLimit) break;
|
|
525
525
|
|
|
526
526
|
const pendingAttributeGoals = env.takePendingAttributeGoals?.() ?? [];
|
|
527
|
-
if (pendingAttributeGoals.length > 0)
|
|
527
|
+
if (pendingAttributeGoals.length > 0) {
|
|
528
|
+
// Goals produced by verify_attributes/3 are invoked by the attribute
|
|
529
|
+
// mechanism, not textually spliced into the caller. Give every
|
|
530
|
+
// awakened goal the same opaque cut boundary as call/1 so a delayed
|
|
531
|
+
// cut cannot prune choices that were made before the suspension.
|
|
532
|
+
const awakened = pendingAttributeGoals.map((pending) => compound('call', [pending]));
|
|
533
|
+
goals = [...awakened, ...goals];
|
|
534
|
+
}
|
|
528
535
|
|
|
529
536
|
const readyDelays = env.takeReadyDelays();
|
|
530
537
|
if (readyDelays.length > 0) {
|
|
531
538
|
const awakened = readyDelays.map(({ goal, module }) => {
|
|
532
539
|
const delayed = copyResolved(goal, env);
|
|
533
540
|
qualifyTerm(delayed, module);
|
|
534
|
-
return delayed;
|
|
541
|
+
return compound('call', [delayed]);
|
|
535
542
|
});
|
|
536
543
|
goals = [...awakened, ...goals];
|
|
537
544
|
}
|
package/test/run-regression.mjs
CHANGED
|
@@ -1990,6 +1990,22 @@ c4 ?- call((!;1)).
|
|
|
1990
1990
|
assertEqual(result.stdout, 'wake(ready, awake).\n', 'freeze answer');
|
|
1991
1991
|
},
|
|
1992
1992
|
},
|
|
1993
|
+
{
|
|
1994
|
+
name: 'Prologue freeze keeps awakened cuts inside the delayed call (issue #81)',
|
|
1995
|
+
run: () => {
|
|
1996
|
+
const result = publicApi.runQuads(`:- use_module(library(prologue)).
|
|
1997
|
+
38
|
|
1998
|
+
?- call( ( (Y=1;Y=2), freeze(X,!), X = c ) ); Y = 3.
|
|
1999
|
+
Y = 1, X = c
|
|
2000
|
+
; Y = 2, X = c
|
|
2001
|
+
; Y = 3.
|
|
2002
|
+
`);
|
|
2003
|
+
assertEqual(result.total, 1, 'quad total');
|
|
2004
|
+
assertEqual(result.passed, 1, 'quad passed');
|
|
2005
|
+
assertEqual(result.failed, 0, 'quad failed');
|
|
2006
|
+
assertEqual(result.stdout, 'quads: 1 run, 1 passed, 0 failed.\n', 'quad report');
|
|
2007
|
+
},
|
|
2008
|
+
},
|
|
1993
2009
|
{
|
|
1994
2010
|
name: 'runQuads covers the remaining finite Prologue examples and arities',
|
|
1995
2011
|
run: () => {
|
package/the-art-of-eyeprolog.md
CHANGED
|
@@ -6283,7 +6283,11 @@ private helpers and same-named predicates in different modules separate.
|
|
|
6283
6283
|
`freeze(?Term,:Goal)` runs `Goal` immediately when `Term` is already nonvariable;
|
|
6284
6284
|
otherwise it delays the goal until `Term` becomes nonvariable. Suspensions are
|
|
6285
6285
|
kept in the logical environment, so bindings and backtracking remain isolated
|
|
6286
|
-
between solution branches.
|
|
6286
|
+
between solution branches. When a suspension wakes, its goal is meta-invoked
|
|
6287
|
+
with its own cut scope: a `!` inside the delayed goal may commit choices made by
|
|
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`.
|
|
6287
6291
|
|
|
6288
6292
|
`dif(?Left,?Right)` posts a delayed finite-tree disequality when its arguments
|
|
6289
6293
|
can still unify. Its residual store is normalized by logical implication:
|