1

据我了解, call_nth(:Goal, ?Nth) 返回 Goal 的第 N 个解决方案,但同时它秘密计算所有先前的解决方案(从第一个到第 (N-1) 个)并简单地忽略它们。如果我们希望将 1 到 N-1 之间的每个 X 的第 X 个解与第 (X+1) 个解进行比较,那么 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).
4

1 回答 1

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]
于 2019-05-23T18:47:18.613 回答