在Prolog中满足一系列目标

Edm*_*und 5 prolog

在Prolog中,我经常通过提供模板(包含变量的结构)然后满足一组约束来解决问题.一个简单的例子可能是:

go(T) :-
    T = [_, _, _],
    member(cat, T),
    member(dog, T),
    member(mouse, T).
Run Code Online (Sandbox Code Playgroud)

实际上,约束集是以其他方式生成的,而不是被修复,我必须编写一个递归谓词来依次满足每个约束:

go(T) :-
    T = [_, _, _],
    findall(A, animal(A), As),
    % satisy member(A, T) for each A in As
    fill_in_animals(T, As)

fill_in_animals(T, []).
fill_in_animals(T, [A|Rest]) :-
    member(A, T),
    fill_in_animals(T, Rest).
Run Code Online (Sandbox Code Playgroud)

请注意,我的问题不是与列表相关的约束,甚至参数也不能总是容易地生成为要传递给上面使用的相对简单的辅助谓词的列表.在实践中,我发现助手是我每次写的一个相当笨拙的谓词,其中:

  1. 接受一个模板,几个用于约束的参数(因此用于将模板的变量绑定到有用的值),以及一个用于指示它最多的约束的变量.
  2. 生成约束以在此迭代中满足,将其应用于模板.
  3. 递归调用自身,以便可以满足剩余的约束.

我正在寻找的是一个基于findall等等的谓词,它将一个接一个地满足一系列目标.就像是:

% satisfyall(:Goal)
% backtracks on Goal but keeps all bindings from each fully satisfied goal.

satisfyall((animal(A), member(A, T)))
Run Code Online (Sandbox Code Playgroud)

我正在寻找的答案不一定是这种形式.实际上,在回溯目标和维护由此产生的每组绑定之间可能存在矛盾.

我希望我已经解释了我的问题,以便能够帮助我们.(如果不让我知道的话.)为这个冗长的问题提前道歉!

更新(2年后)

我会在今天晚些时候试一试并更新我的问题!

请注意,我从未说过我会在尝试的同一天更新问题. ;-)

@CapelliC引导我朝着正确的方向前进,我发现了一种似乎运作良好的模式:

?- Gs = [member(red),member(blue)], T = [_,_], foreach(member(G, Gs), call(G, T)).
T = [red, blue] ;
T = [blue, red] ;
Run Code Online (Sandbox Code Playgroud)

Cap*_*liC 1

您肯定知道回溯将需要撤消已完成的更改。这是Prolog算法的核心,也是Prolog力量的源泉。

当涉及到更常见的计算时,例如那些必然涉及副作用或循环的计算,这也是一个弱点。

找到正确的方法来强制我们的规则沿着确定性路径运行可能很困难,可能是因为这不是 Prolog 应该工作的方式。

好吧,现在,停止哲学咆哮,让我们看看 Prolog 的大师们为我们提供了什么:SWI-Prolog 提供了库(聚合),您可以在其中找到foreach,我认为它可以满足您的需求:

?- foreach(animal(X), member(X,L)).
L = [cat, dog, mouse|_G10698] .
Run Code Online (Sandbox Code Playgroud)

研究如此复杂的内置函数可以为您的实现提供一些想法(?- edit(foreach).从控制台使用来检查源代码)。

请注意,它将生成器和目标分开,而在您的问题中,它们毫无希望地结合在一起。当然,这需要能够在生成器部分上回溯。

顺便说一句,尝试理解文档页面中列出的小示例。diff/2 过于复杂,但您确实需要掌握绑定的行为才能概括您的递归谓词。

华泰