Good points. I’d like to add two more
-
When looking at the findall/3 as alternative to
maplist(convert,List,Ys)
we should note that an unexpected failure of convert/2 silently looses an answer. A complete failure is way easier to find and debug than a slightly different answer. For the same reason it is often wise to use forall/2 rather than classical failure driven loops.findall(Y, (member(X,List), convert(X,Y)), Ys)
-
Be aware that using findall/3, bagof/3, etc. copies your data. If it is ground data that merely wastes space and time. findall/3 creates fresh variables. bagof/3 and setof/3 preserve these variables, but as the cost of even more copying. Things get even harder when attributed variables are involved. In some cases you can freely copy these but some constraint solvers may have expectations of the constraint network that are violated by copying.
So, if you have a list of stuff it is typically desirable to use maplist/2, include/3 and related meta predicates to turn it into another list. In many cases a set of answers to a query is a more desirable representation of a set though as you can use simple plain logic to filter, extend or transform this set. Moreover you can deal with infinite sets as you are basically streaming data.