Prolog max列表中的最大值

时间:2014-09-14 22:58:00

标签: prolog

mymax([], 'list_is_empty').
mymax([Head | []], Max) :- (Max >= Head).
mymax([Head | List], Max) :- (Max > Head), mymax(List,Max).

这似乎可以正常使用mymax([1,5,3],5)等查询,但无法正常工作 找到最大值并给出以下错误:

ERROR: >/2: Arguments are not sufficiently instantiated

我有点理解为什么会这样,尽管我无法用语言表达。 这可以修复,还是我的算法完全错误?

4 个答案:

答案 0 :(得分:3)

与Head比较时,Max仍未绑定,导致错误。

你可以用这种方式简化:

mymax([Max], Max).
mymax([Head | List], Max) :-
  mymax(List, MaxList),
  ( Head > MaxList -> Max = Head ; Max = MaxList ).

编辑

我试图尽量减少对代码的修改,但正如@mat指出的那样,这只适用于表达式列表,例如数字。然后你可以写

1 ?- mymax([4+1, 3+3], N).
N = 3+3

如果您不确定列表的域名(即其元素类型),最好使用term comparison运算符:

 ( Head @> MaxList -> ... )

但现在:

?- mymax([4+1, 3+3], N).
N = 4+1

答案 1 :(得分:2)

(>=)/2(>)/2之类的低级算术运算符仅在其参数实例化为具体算术表达式时才起作用。

要使您的程序也适用于?- mymax(List, Max).等更常见的查询,请考虑使用约束,这些约束在所有主要的Prolog实现中都可用。

例如,在SICStus或SWI-Prolog中使用有限域约束:

:- use_module(library(clpfd)).

list_max([L|Ls], Max) :-
    list_max_(Ls, L, Max).

list_max_([], Max, Max).
list_max_([L|Ls], Max0, Max) :-
    Max1 #= max(Max0,L),
    list_max_(Ls, Max1, Max).

或等效地,使用foldl/4

:- use_module(library(clpfd)).

list_max([L|Ls], Max) :- foldl(x_y_max, Ls, L, Max).

x_y_max(X, Y, Max) :- Max #= max(X, Y).

示例查询和一些结果:

?- list_max(Ls, Max).
Ls = [Max] ;
Ls = [_G551, _G554],
Max#>=_G551,
Max#=max(_G551, _G554),
Max#>=_G554 ;
Ls = [_G636, _G639, _G642],
_G657#>=_G636,
_G657#=max(_G636, _G639),
Max#>=_G657,
_G657#>=_G639,
Max#=max(_G657, _G642),
Max#>=_G642.

答案 2 :(得分:1)

如果你想让它变得简单,排序,反转,请抓住头脑:

mymax(List, Max) :-
    sort(List, Sorted),
    reverse(Sorted, [Max|_]).

否则,取第一个元素并将其设置为最大元素(到目前为止)。然后查看列表的其余部分,如果找到大于当前最大值的元素,请用它替换当前最大值。这就是@CapelliC正在做的事情(使用if-then-else控制谓词)。

一种方法不使用使用if-then谓词,改为使用谓词子句,并利用ISO谓词compare

mymax([First|Rest], Max) :-
    mymax_1(Rest, First, Max).
mymax_1([], Max, Max).
mymax_1([This|Rest], Current, Max) :-
    compare(Cmp, This, Current),
    mymax_2(Cmp, Rest, This, Current, Max).
mymax_2(>, Rest, This, _, Max) :-
    mymax_1(Rest, This, Max).
mymax_2(=, Rest, _, Current, Max) :-
    mymax_1(Rest, Current, Max).
mymax_2(<, Rest, _, Current, Max) :-
    mymax_1(Rest, Current, Max).

但是这种写作谓词的风格并不是很受欢迎,可能是因为它过于明确并且涉及打字过多。另一方面,它是尾递归和确定性的。当您将变量作为第一个参数传递时,它也不会中断:

?- mymax(L, 13).

您还可以从任何开源Prolog实现(例如SWI-Prolog)的标准库中查看max_list/2max_member/2的实现,以获得更实用的方法(但仍然使用if-then-else)。

答案 3 :(得分:1)

要查找列表的最大值,您可以说它是此列表的成员,并且此列表中没有任何元素大于它:

my_max(L, V) :-
    member(V, L),
    \+((member(X, L), X > V)).