Reputation: 24593
Extending on this question Can be this lisp function be implemented recursively? , is it possible to have all combinations in Prolog if the lists are represented like following:
items1(1, 2, 3).
items2(4, 5).
I can get the answer with following format of data:
items1(1).
items1(2).
items1(3).
items2(4).
items2(5).
?- findall((A,B), (items1(A), items2(B)), L).
L = [ (1, 4), (1, 5), (2, 4), (2, 5), (3, 4), (3, 5)].
I checked the permutation predicate from http://www.swi-prolog.org/pldoc/man?predicate=permutation/2 but that is for a different purpose.
Upvotes: 1
Views: 638
Reputation:
You seem to have already solved your problem quite nicely, by normalizing your database. It is inconvenient to represent a list [I_1, I_2, ..., I_n]
as a fact items(I_1, I_2, ..., I_n).
. Lists are meant for (possibly ordered) collections that have 0 or more elements; facts are usually meant for tables with a preset number of columns, with one fact per row. And these two representations:
[a, b, c]
(a list), anditem(a). item(b). item(c).
(a table of facts)are in fact very similar. Choosing one or another is a matter of how you want to use it, and it is quite easy (and common) to convert from the one to another in your program. For example, ?- member(X, [a, b, c]).
is about the same as ?- item(X).
when you have (2) defined. The Prolog list version of the question you linked would be:
combo(L1, L2, X-Y) :-
member(X, L1),
member(Y, L2).
And then:
?- combo([1,2,3], [4,5], R).
R = 1-4 ;
R = 1-5 ;
R = 2-4 ;
R = 2-5 ;
R = 3-4 ;
R = 3-5.
A bit less inconvenient (but still unnecessary) would be to write items([a, b, c]).
, so you have one argument, a list of all items. Then, you can do:
?- items(Is),
member(X, Is).
If you really have something like items(a, b, c).
, and you know that you have exactly three items, you could still do:
?- items(A, B, C),
member(X, [A, B, C]).
If you don't know at compile time the arity of items
, you need to examine the program at run time. If your program looks as in your question:
items1(1, 2, 3).
items2(4, 5).
Then you could for example do:
?- current_predicate(items1/N), % figure out the arity of items1
length(Is, N), % make a list of that length
Fact =.. [items1|Is], % create a callable term
Fact, % call the term to instantiate Is
member(X, Is). % enumerate the list
As you see, quite round-about.
One more comment: It is unusual to use (A,B)
as a "tuple" in Prolog. For a pair, you would usually write A-B
, and if you don't know how many elements you have, it's usually just a list, for example [A,B|Rest]
. See this answer and the comments below it for more detail.
Upvotes: 1