Prolog:没有累加器的谓词最大值

use*_*349 7 list prolog integer-arithmetic

是否有可能在max/2 没有累加器的情况下创建谓词,因此max(List, Max)当且仅当MaxList(整数列表)的最大值时才是真的?

Wil*_*sem 4

是的,您可以在递归步骤之后计算最大值。喜欢:

max([M],M).          % the maximum of a list with one element is that element.
max([H|T],M) :-
    max(T,M1),       % first calculate the maximum of the tail.
    M is max(H,M1).  % then calculate the real maximum as the max of
                     % head an the maximum of the tail.
Run Code Online (Sandbox Code Playgroud)

例如,该谓词适用于浮点。尽管如此,最好使用累加器,因为大多数 Prolog 解释器都使用尾调用优化 (TCO),并且带有累加器的谓词往往与尾调用一起使用。因此,如果您想要处理巨大的列表,带有 TCO 的谓词通常不会出现堆栈溢出异常。

正如@Lurker所说is只有在列表完全接地的情况下才有效:它是一个有限列表,并且所有元素都接地。但是,您可以使用 Prolog 的约束逻辑编程clp(fd)

:- use_module(library(clpfd)).

max([M],M).          % the maximum of a list with one element is that element.
max([H|T],M) :-
    max(T,M1),       % first calculate the maximum of the tail.
    M #= max(H,M1).  % then calculate the real maximum as the max of
                     % head an the maximum of the tail.
Run Code Online (Sandbox Code Playgroud)

然后您可以例如调用:

?- max([A,B,C],M),A=2,B=3,C=1.
A = 2,
B = M, M = 3,
C = 1 ;
false.
Run Code Online (Sandbox Code Playgroud)

因此,在调用之后max/2,通过接地ABC,我们得到M=3

  • 此处使用“is/2”不会满足OP的*if and only if*规定。使用 CLP(FD),`M #= max(M, M1)`,然后您还可以通过在递归调用之前应用此约束来获得回尾递归。这也将启用诸如“max([A, B, 4], 5)”之类的查询。 (2认同)