The thing I wanted to do was generate all combinations of elements from a given list. E.g.: From [a,b,c], I might want:
[]
[a]
[b]
[c]
[a,a]
[a,b]
[a,c]
[b,a]
...
And so on. Perhaps there is a magical prolog one-liner that does this. If so, I would love to hear it.
However, my question is less about solving this particular problem and more of a request that someone explain some subtleties of Prolog's search algorithm for me.
So here's what I did first to solve the above problem:
members([], _).
members([X|Xs], List) :-
member(X,List),
members(Xs, List).
This works great but returns all possible results, and not in a great order:
[]
[a]
[a,a]
[a,a,a]
Okay, that's no problem. I really just want all combinations up to a certain length. So I decided to first get the ones that have exactly a particular length:
membersWithLength(Members, List, Bound) :-
L = Bound,
length(Members, L), members(Members, List).
This works great, e.g. for length 2:
[a,a]
[a,b]
[a,c]
...
And so on. Now my attempt to use clpfd to leverage the above function to get all lists up to a certain length went awry:
:- use_module(library(clpfd)).
membersLessThan(Members, List, Bound) :-
L in 0..Bound, % I also tried L #=< Bound
membersWithLength(Members, List, L).
Kind of works. Finds the right results (lists with length less than Bound). But after it finds them, it loops continuously searching for more results. E.g. for length 2:
[]
[a]
[b]
[c]
[a,a]
[a,b]
...
[c,c]
Hangs looking for more solutions.
I guess this is the heart of my question. Can someone explain why (according to the trace) prolog continues to check larger and larger lists as possible solutions, even though they are all doomed to failure? And can someone tell me if there's a way to help prolog avoid this doomed journey?
I ultimately used the following code to solve the problem, but I was disappointed that I couldn't figure out how to use clpfd's integer constraints to constrain the size of the lists.
membersLessThan_(Members, List, Bound) :-
numlist(0,Bound,ZeroToBound),
member(L, ZeroToBound),
membersWithLength(Members, List, L).
Here is all the relevant code on SWISH: http://swish.swi-prolog.org/p/allcombos.pl