Chris2015
Chris2015

Reputation: 115

Handling all possible results in prolog

I have a clause is_adjacent([X1,Y1], [X2,Y2]) which is true, when [X2,Y2] is a neighbor of [X1,Y1]. I get all possible results (four) if i ask is_adjacent([2,2], [X,Y]), in this case:

is_adjacent([2,2],[X,Y]).
X = 2,
Y = 3 ;
X = 3,
Y = 2 ;
X = 2,
Y = 1 ;
X = 1,
Y = 2.

I want to use this behavior in another clause:

anotherClause :-
    is_adjacent([2,2],[X,Y]),
    [to be continued...].

Now, how can i work automatically with every possible result? For example if i want to check if every single result is a member of a specific list.

Thanks for your answers!

Upvotes: 0

Views: 792

Answers (4)

ony
ony

Reputation: 13223

There is a way to transform ∀ (for all) into ∃ (there exists) with double-not approach:
∀x.f(x) = ¬¬∀x.f(x) = ¬∃x.¬f(x)

anotherClause :- \+(notAnotherClause).
notAnotherClause :- is_adjacent([2,2],[X,Y]), \+(memberchk([X,Y], SomeList)).

Idea is that we search for existence of negative result within all alternatives and absence of that actually means "for all variants".

P.S. \+/1 (\+(Goal)) sometimes written as not/1 (not(Goal))

Upvotes: 0

CapelliC
CapelliC

Reputation: 60024

there is forall/2, that seems to fit your requirements:

% this fails because not all results are in list
anotherClause :-
    forall(is_adjacent([2, 2], [X, Y]),
           memberchk([X, Y], [[2, 3], [3, 2]])).

% this succeed, all results are in list
anotherClause :-
    forall(is_adjacent([2, 2], [X, Y]),
           memberchk([X, Y], [[2, 3], [3, 2], [1, 2], [2, 1]])).

for test purpose, I coded is_adjacent this way:

is_adjacent([A, B], [X, Y]) :-
    member(U / V, [1 / 0, 0 / 1, -1 / 0, 0 / -1]),
    X is A + U, Y is B + V.

Upvotes: 1

Mark Bolusmjak
Mark Bolusmjak

Reputation: 24409

If you want to collect all solutions, I think you might be looking for the set of predicate setof. This finds all solutions of a predicate.

setof([X,Y], is_ajacent([2,2],[X,Y], Z)

then

Z = [[2,3], [1,2], ...]

If you don't want to collect all solutions, but simply do something for each solution, then do as dasblinkenlight second solution shows. specifically fail at the end so Prolog tries the next solution. Then finally succeed.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726699

To check every result of is_adjacent against some other rule, all you need to do is to write that rule in terms of X and Y, like this:

anotherClause :-
    is_adjacent([2,2],[X,Y]),
    X > 0,
    Y > 0,
    check_x_and_y(X, Y, Result),
    ...

and so on. When you evaluate anotherClause, Prolog will unify X and Y with the first set of values, and then go on with the rest of the clause (above, it's checking that X and Y are greater than zero, and evaluating the two variables with the check_x_and_y rule. Once the rule comes up with a set of assignments, it gives them to you, and lets you stop or continue. If you want to always continue until the whole set is exhausted (e.g. to print all assignments of X and Y), the pattern looks like this:

anotherClause :-
    is_adjacent([2,2],[X,Y]),
    print_x_and_y(X,Y),
    fail.

anotherClause.

The first rule goes through each assignment of X, Y, prints them, and then fail to trigger re-evaluation. The second rule is a catch-all fact to stop further evaluation.

Here is a link to a demo on ideone that prints all pairs of adjacent cells.

Upvotes: 0

Related Questions