The PROLOG rule returns only the first match

I am trying to implement the findall predicate in Prolog (yes, I know that it is built-in, this is for assignment).

This is written as follows:

my_findall(N,P,Pred,L) :- Pred, not(new(N,P)), !, assert(new(N,P)), my_findall(N1,P1,Pred,L1), L=[N,P,L1], retract(new(N,P)). my_findall(_,_,_, []). 

For some reason, it gives me the first solution and stops there, as if the second call to my_findall failed. As far as I understand, the backtracking mechanism should cover all possible options, which should include all the options for calling Pred (N, P), therefore, despite the fact that the second call should fail on the first try (the first option that tried use Pred, it has already been confirmed), he must first try all the other options before abandoning my_findall ((,, _, []).

If this is not how it works, is there a way to make this behavior not completely rewrite the solution?

+4
source share
1 answer

Your Pred contains unrelated variables. When you call Pred in the first iteration, these variables are associated with the first possible values. In your recursive step, Pred already has bound variables, and they cannot change values. So ... this solution will not work.

Tracking from SWI-Prolog (I had to rename new / 2 to item / 2 for some reason):

First level (call: my_findall (A, B, member (p (A, B), [p (1,2), p (3,4)]), L).).

  Call: (7) my_findall(_G819, _G820, member(p(_G819, _G820), [p(1, 2), p(3, 4)]), _G840) ? creep Call: (8) lists:member(p(_G819, _G820), [p(1, 2), p(3, 4)]) ? creep Exit: (8) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep 

We get p (A, B) = p (1,2). At this point, A is associated with 1, B is associated with 2.

 ^ Call: (8) not(item(1, 2)) ? creep Call: (9) item(1, 2) ? creep Fail: (9) item(1, 2) ? creep ^ Exit: (8) not(item(1, 2)) ? creep 

Well, there is no (1,2) element in the database.

 ^ Call: (8) assert(item(1, 2)) ? creep ^ Exit: (8) assert(item(1, 2)) ? creep 

Now element (1,2) is correct. Recursive call:

  Call: (8) my_findall(_L215, _L216, member(p(1, 2), [p(1, 2), p(3, 4)]), _L199) ? creep 

Let me get another do Pred solution:

  Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep ^^^^^^^ 

See underlined snippet?

For this technique, you should probably copy Pred by recursively changing N and P to new variables. For each iteration, you need to β€œcreate” a new pair of N and P. Check copy_term / 2 ( http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2 ).

+5
source

All Articles