rnso
rnso

Reputation: 24593

Permutations including all members in Prolog

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

Answers (1)

user1812457
user1812457

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:

  1. [a, b, c] (a list), and
  2. item(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

Related Questions