找到所需的解决方案而无需多次使用call_nth / 2或使用findall / 3?

时间:2019-04-18 23:04:53

标签: prolog time-complexity meta-predicate

据我了解,call_nth(:Goal,?Nth)返回目标的第N个解,但同时它秘密地计算了所有先前的解(从第1个到第(N-1)个),并忽略了它们。如果我们希望将第X个与第(X + 1)个解决方案进行比较,则介于1和N-1之间的每个X都将变得非常昂贵,因为call_nth基本上保持了在先前步骤中已经计算出的解决方案。我想知道是否有一种更有效的方法来解决这种形式的问题,而无需使用findall / 3。

(一个典型的例子是下面的脚本,如果谓词中不存在GOAL,则该脚本将找到GOAL或与其最接近的最大值。)

num(10).
num(20).
num(30).
num(40).
num(50).

search_for_goal(GOAL,RESULT):-
    search_for_goal(GOAL,0,1,RESULT).

search_for_goal(GOAL,_,COUNTER,GOAL):-
    call_nth(num(GOAL),COUNTER),!.
search_for_goal(GOAL,CURRENT_MAX,COUNTER,RESULT):-
    call_nth(num(X),COUNTER),
    COUNTER2 is COUNTER+1,
    (  X=<CURRENT_MAX->
       search_for_goal(GOAL,CURRENT_MAX,COUNTER2,RESULT)
    ;  search_for_goal(GOAL,X,COUNTER2,RESULT)
    ).
search_for_goal(_,CURRENT_MAX,COUNTER,CURRENT_MAX):-
    \+call_nth(num(_),COUNTER).

1 个答案:

答案 0 :(得分:2)

使用SWI-Prolog,可以通过Prolog引擎实现。为了说明这一点,请考虑我自己的findall / 3谓词版本,该谓词仅返回偶数解。

my_findall(Templ, Goal, List) :-
    setup_call_cleanup(
    engine_create(Templ, Goal, E),
    get_answers(E, List),
    engine_destroy(E)).

get_answers(E, [H|T]) :-
    /* Skip next solution. */
    engine_next(E, _),
    /* Take next solution. */
    engine_next(E, H),
    !,
    get_answers(E, T).

get_answers(_, []).

查询方式:

my_findall(X,member(X,[1,2,3,4]),Y)

仅返回n为偶数的第n个解。

Y = [2, 4]