【问题标题】:PROLOG rule returns only first matchPROLOG 规则仅返回第一个匹配项
【发布时间】:2009-07-08 14:44:42
【问题描述】:

我正在尝试在 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((,),_, [])。

如果它不是这样工作的,有没有办法在不完全重写解决方案的情况下强制这种行为?

【问题讨论】:

  • 您正在使用哪个 prolog 解释器?
  • 内置的 findalls 是 findall/3 和 findall/4。你想实现哪一个?

标签: prolog


【解决方案1】:

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

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

第一级(调用: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

我们得到 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

好的,数据库中没有item(1,2)。

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

现在 item(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 (http://www.swi-prolog.org/pldoc/doc_for?object=copy_term%2f2)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-24
    • 2011-07-14
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    相关资源
    最近更新 更多