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.