There’s some discussion about the “exists” notation and other nuances of findall/setof (and other aggregators) here:
You can read English^some_pred(English, Spanish) as "there exists an English such that some_pred(English, Spanish)`.
If the English^ were missing, then there would be an implicit “there exists” outside the bagof and you’d generate only a single result. If you try translate_bag(["One", "Two"]) with English^ removed, you’ll see that it backtracks, giving one result at a time:
?- translate_bag(["One", "Two"], Z).
Z = ["Uno"] ;
Z = ["Dos"].
In general, I avoid findall (based on Richard O’Keefe’…
Better to use bagof/3 or setof/3. As Lee Naish and Richard O’Keefe have pointed out, findall is unsound if the Template doesn’t capture all the free variables in the Goal.
bagof and setof allow you to mark variables as existentially qualified (although you might want to define an auxiliary predicate for clarity), and also allow backtracking over the other free variables. The downside of using bagof and setof is that if you want “no solutions” to result in [], you need to wrap it: (bagof(X, pre…
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 r…
As a general rule, there shouldn’t be any “unused” variables in a predicate to findall/3, bagof/3, setof/3 – use an auxiliary predicate if necessary. And be especially careful of “_
” in the predicate to findall/3 et al – in that context, it almost never does what you think it does.
2 Likes