Aggregation

Richard O’Keefe (Craft of Prolog page 363) quotes Lee Naish in pointing out that findall/3 can be used to define all sorts of nasty (non-logical) things such as not/1 and var/1:

not(Goal) :- findall(., Goal, []).
var(Var) :- findall(., (Var = a; Var = b), [_,_]).

If you want to conflate failure with [], it’s easy enough:

setof_or_nil(Template, Goal, Result) :-
    ( setof(Template, Goal, Result) -> true ; Result = [] ).

and it’s up to you to confirm that Goal and Template allow only sound results.

And if you don’t like the way existential variables are specified with bagof and setof, see library(solution_sequences). And library(aggregate) gives some generalizations on bagof/setof.

2 Likes