Thank you for the insight @jan!
You are right in saying that solve/4, and in particular the findnsols/4 solution in pengines.pl is the problem. Here’s how I confirmed it.
1) Trying to use once/1
First I though I could get around the problem with a clever use of once/1: I noted at a recursive repl that this invocation loses the CHR constraints (here sugar/0 is a CHR constraint):
findnsols(1, X, (sugar, member(X, [1,2])), Xs).
But this one keeps them:
once(findnsols(1, X, (sugar, member(X, [1,2])), Xs)).
Interestingly this one loses them again:
once(findnsols(1, X, (sugar, member(X, [1])), Xs)).
I think this behavior has to do with leaving choicepoints but I’d like to understand it better.
2) Changing findsols_no_empty/4 in pengines.pl
The most ergonomic way to change pengines.el seemed to rewrite the findsols_no_empty/4 predicate. I could get it working in 2 ways:
findnsols_no_empty(N, Template, Goal, List) :-
call(Goal),
List = [Template].
- The one trying to use
once/1 but adding a fake predicate to retain a choice point (?).
findnsols_no_empty(N, Template, Goal, List) :-
once(findnsols(N, Template, (Goal, member(_, [1,2])), List)),
List \== [].
I like the second solution you proposed more, but I’m not familiar with all the implication that changing this code could have for SWISH, so I would appreciate more guidance on the type of solution that you are envisioning here.