高阶“解”谓词

时间:2017-11-11 03:10:09

标签: prolog lambda-prolog

我正在使用缺少findall的更高阶Prolog变体。

在此处实施我们自己的findall还有另一个问题:Getting list of solutions in Prolog

低效的实施是:

parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob

list_parents(A, Es, [X|Xs]) :-
   parent(X, A),
   \+ member(X, Es),
   list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).

高效的

  

需要一个“解决方案”高阶谓词:

list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)

什么是solutions?我可以在更高阶lambda Prolog中实现我自己的solutions谓词吗?

2 个答案:

答案 0 :(得分:3)

,如果findall/3不可用,您可以通过动态数据库来实施。

例如,对于父母的具体用例:

list_parents(_) :-
        parent(P, _),
        assertz(parent(P)),
        false.
list_parents(Ps) :-
        phrase(retract_parents, Ps).

retract_parents -->
        (   { retract(parent(P)) } ->
            [P],
            retract_parents
        ;   []
        ).

示例查询:

?- list_parents(Ps).
Ps = [pam, george].

您可以将此与sort/2结合使用,以获得渐近最优的性能,避免“天真”解决方案的二次开销,以消除重复项。

小心但是:首先,这是不是线程安全的。为了使其成为线程安全的,您需要添加有关当前线程的更多信息。

其次,如果您以这种方式实施完整的findall/3,则必须处理嵌套 findall/3来电。

这样做的一种方法是断言两个的术语:

  • solution(S),例如solution(parent(pam)),表示通过最近的findall/3电话回复找到的具体解决方案
  • mark,表示新findall/3从此处开始

收集解决方案时,您只能使用最新的mark

请参阅Richard O'Keefe的书,了解这些问题。

答案 1 :(得分:3)

如果你的Prolog有某种非回溯分配,比如SWI-Prolog 'global' variables,你可以用这种方式实现(注意,简单的代码):

:- meta_predicate solutions(0, ?).
:- meta_predicate solutions(+, 0, ?).

solutions(G, L) :-
    solutions(G, G, L).

solutions(P, G, L) :-
    ( nb_current(solutions_depth, C) -> true ; C=1 ),
    D is C+1,
    nb_setval(solutions_depth, D),
    atom_concat(solutions_depth_, D, Store),
    nb_setval(Store, []),
    (   G,
        nb_getval(Store, T),
        nb_setval(Store, [P|T]),
        fail
    ;   nb_getval(Store, R)
    ),
    nb_delete(Store),
    nb_setval(solutions_depth, C),
    reverse(R, L).

使用'全球'变量导致更高效的执行WRT动态数据库(断言/撤销),并且(在SWI-prolog中)甚至可以在多线程应用程序中使用。

修改

感谢@false评论,在反向/ 2之前移动剪切,并为可重入调用引入了一个堆栈:例如

?- solutions(X-Ys,(between(1,3,X),solutions(Y,between(1,5,Y),Ys)),S).
S = [1-[1, 2, 3, 4, 5], 2-[1, 2, 3, 4, 5], 3-[1, 2, 3, 4, 5]].

修改

这是解决方案/ 3的变体,按顺序构建结果列表,以避免最后的反向/ 2调用。将结果添加到列表尾部有点棘手......

solutions(P, G, L) :-
    ( nb_current(solutions_depth, C) -> true ; C=1 ),
    D is C+1,
    nb_setval(solutions_depth, D),
    atom_concat(solutions_depth_, D, Store),
    (   G,
        ( nb_current(Store, U/B) -> B = [P|R], Q = U/R ; Q = [P|T]/T ),
        nb_setval(Store, Q),
        fail
    ;   ( nb_current(Store, L/[]) -> true ; L = [] )
    ),
    nb_delete(Store),
    nb_setval(solutions_depth, C).