da1g
da1g

Reputation: 117

Predicate gives list of unbound variables instead of all possible lists

Let's say I have a list L1 = [1,2,3], I want to write a predicate that can find all permutations of this list i.e

[1,2,3]
[1,3,2]
[2,1,3]
[2,3,1]
[3,1,2]
[3,2,1]

Note: I know permutation(L1, L2). does exactly this, but I want to write my own predicate that does this for an exercise.

I'm a prolog rookie, so I thought lets first make a predicate that returns truewhen two lists L1 and L2 are permutations of eachother. The requirements for that are:

  1. They need to be the same length
  2. Every element in L1 has to be in L2

So I came up with this:

permute(L1,L2):-
    forall(member(X,L1), member(X,L2)), % every element that is a member in L1 has to be a member in L2
    length(L1,A), % the length of the list L1 is A
    length(L2,A). % AND the length of the list L2 is A

So when I query permute([1,2,3], [1,3,2]).I do get true as expected, and permute([1,2,3], [1,3]). and permute([1,2,3], [1,3,4]). both give false. So my predicate works to see if 2 lists are permutations of eachother.

But if I ask: permute([1,2,3], A). I want to be able to see all valid A, i.e all permutations of [1,2,3]. Instead I get unbounded variables. Something like A = [_942, _948, _954].

Why does this happen, why can't i look through all possible lists A? Is there a simple way to modify my code to make that happen?

Upvotes: 2

Views: 215

Answers (1)

Will Ness
Will Ness

Reputation: 71074

First of all your two points definition is wrong. According to it, permute( [1,1,2], [1,2,2]) should hold (and it does).

The "simple" way is to use select/3,

select( [A|B], X):- select(A, X, Y), select(B, Y).
select( [], []).

And it works, but only in one direction. Even adding (simple) same_length doesn't help:

permute( A, B):- same_length( A, B), select( B, A).

same_length( A, B):- length(A, N), length(B, N).   % wrong

% permute( [1,2,3], X).    % OK
% permute( X, [1,2,3]).    % doesn't terminate after the last solution

No, same_length/2 must be defined carefully, as

same_length( [], []).
same_length( [_|A], [_|B]):- same_length(A, B).

Then permute is OK in both directions.

Upvotes: 2

Related Questions