I think I missed the real question by @emiruz. The foldl
at the end of their question: in library(aggregate) there are templates, but you cannot provide your own aggregation operation. I think @j4n_bur53 showed something in another thread but I can no longer find it. What would be a possible implementation for a fold for a backtrackable goal?
The idea is just to provide the aggregation loop though a meta-predicate. The first argument is an aggregation operation that is applied in turn to the solutions of the backtrackable goal. Here is a naive attempt:
foldl_bt(Op, Goal, V0, V) :-
State = state(V0),
( call(Goal),
arg(1, State, S0),
call(Op, S0, S),
nb_setarg(1, State, S),
fail
; arg(1, State, V)
).
This seems to work. If I define:
sum(A, B, S) :- S is A + B.
then:
?- aggregate_all(sum(X), between(1, 3, X), Sum).
Sum = 6.
?- foldl_bt(sum(X), between(1, 3, X), 0, Sum).
Sum = 6.
?- foldl_bt(sum(1), between(1, 3, X), 0, Count).
Count = 3.
It also nicely reverses concatenation like the original foldl.
?- foldl(atom_concat, [a,b,c], '', L).
L = cba.
?- foldl_bt(atom_concat(X), (X=a ; X=b ; X=c), '', L).
L = cba.
What am I missing?
PS: Back to the original question
Depending on the processing that is involved, this could look roughly like this:
foldl_bt(aggregation_op(X),
( foo(A, B),
bar(B, C),
baz(C, X)
), 0, Result).