Christophe De Troyer
Christophe De Troyer

Reputation: 2922

Do not backtrack over single argument

I have a predicate that, given a list, creates a partition for this list (i.e it splits into two parts). This predicate can thus generate multiple solutions.

For each part of the partition, I will generate all the possible permutations.

And then for these permutations I will do some sort of test.

Suppose the following:

:- generatePartition(List, A, B),
   permutation(A,Perm1),
   permutation(B, Perm2),
   test(Perm1),
   test(Perm2).

The point here is, that if the test succeeds for Perm1, this is the only Perm1 I need.

If next, the test fails for Perm2, I want to try every possible permutation for Perm2. If they all fail I immediatly want a new partition. I do not want to generate a different permutation for A.

I tried the following (add some sort of scope to the cut):

:- generatePartition(List, A, B),
   permutation(A,Perm1),
   permutation(B, Perm2),
   (
       test(Perm1),!
   ),
   test(Perm2).

Is there any possible solution to this? I broke my brain on this one today :)

Upvotes: 2

Views: 99

Answers (1)

Will Ness
Will Ness

Reputation: 71065

You can achieve this with IF-THEN construct:

:- generatePartition(List, A, B),
   (   permutation(A,Perm1),
       test(Perm1)             % just one Perm1 for which test succeeds
   ->
       permutation(B, Perm2),
       test(Perm2)             % all the Perm2 such that test succeeds
   ).

In general, you can create scope by creating an auxiliary named predicate and using it instead of a block of code. Then you can use cut inside that auxiliary predicate.

But there's already a predicate once/1, as pointed out by [user:false] in the comments:

:- generatePartition(List, A, B),
   once( (permutation(A,Perm1), test(Perm1)) ),
   permutation(B, Perm2),
   test(Perm2).

Upvotes: 2

Related Questions