PROLOG规则只返回第一个匹配项

PROLOG规则只返回第一个匹配项,prolog,Prolog,我试图在Prolog中实现findall谓词(是的,我知道它是内置的,这是用于赋值的) 内容如下: 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(_,_,_, []). 出于某种原因,它只给了我第一个解决方案,然后停在那里,好像对my_findall的第二次调用失败了

我试图在Prolog中实现findall谓词(是的,我知道它是内置的,这是用于赋值的)

内容如下:

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(_,_,_,  []).
出于某种原因,它只给了我第一个解决方案,然后停在那里,好像对my_findall的第二次调用失败了。据我所知,回溯机制应该检查所有可能的选项,其中应该包括调用Pred(N,P)的所有选项,因此即使第二次调用在第一次尝试时失败(为Pred尝试的第一个选项已经被断言),它也应该在放弃并转到my_findall((,)之前先尝试所有其他选项,u,[])


如果这不是它的工作原理,有没有一种方法可以在不完全重写解决方案的情况下强制执行这种行为

您的Pred包含未绑定的变量。在第一次迭代中调用Pred时,这些变量绑定到第一个可能的值。在递归步骤中,Pred已经有绑定变量,它们不能更改值。所以这个解决方案行不通

来自SWI Prolog的跟踪(出于某些原因,我不得不将new/2重命名为item/2):

第一级(呼叫:my_findall(A,B,成员(p(A,B),[p(1,2),p(3,4)]),L)。)

我们得到了p(A,B)=p(1,2)。此时,A与1绑定,B与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
好的,数据库中没有项目(1,2)

^  Call: (8) assert(item(1, 2)) ? creep
^  Exit: (8) assert(item(1, 2)) ? creep
现在第(1,2)项为真。递归调用:

   Call: (8) my_findall(_L215, _L216, member(p(1, 2), [p(1, 2), p(3, 4)]), _L199) ? creep
让我们获得另一个解决方案,执行Pred:

   Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep
                          ^^^^^^^
看到划线部分了吗


为了让这项技术发挥作用,您可能应该复制Pred,递归地将N和p更改为新变量。对于每次迭代,您必须“创建”新的N和P对。请检查copy_term/2()。

您正在使用哪个prolog解释器?内置的findall是findall/3和findall/4。你想实现哪一个?
   Call: (9) lists:member(p(1, 2), [p(1, 2), p(3, 4)]) ? creep
                          ^^^^^^^