获取列表的最小值

时间:2011-11-08 02:45:33

标签: list prolog syntax-error minimum iso-prolog

我正在尝试查找列表的最小值(作为学习体验,因此没有min)。

我的方法如下:

minimo([X], X).
minimo([X,Y|Tail], N):-
    (X > Y, minimo([Y,Tail], Y));
    (X <= Y, minimo([X,Tail], X)).

这给了我以下错误:

  

语法错误:操作员期望

所以我的问题是:

  • 导致语法错误的原因是什么?
  • 如果修复它确实给出了正确的值,我将自己尝试一下,但这实际上是一种正确的方法吗?

提前致谢。

4 个答案:

答案 0 :(得分:4)

您的计划中有几个错误:

  1. 正如Joe Lehmann所指出的,没有'<='/2。必须是'=<'/2

  2. 当你递归调用minimo/2时,你构造错误的列表。而不是[Y,Tail]使用[Y|Tail]。否则,您将获得一个列表作为第二个元素。

  3. minimo/2的递归调用的第二个参数绑定到YX。相反,它必须绑定到N。否则,您的N将永远不会被实例化。

  4. 您可以通过添加剪辑或使用if-then-else('->' + ;)来进一步改进您的计划:

    minimo([X], X) :- !.
    minimo([X,Y|Tail], N):-
        ( X > Y ->
            minimo([Y|Tail], N)
        ;
            minimo([X|Tail], N)
        ).
    

答案 1 :(得分:4)

除了已发布的其他版本之外,还要考虑没有if-then-else的版本,并使用更具描述性的关系名称(将列表与其最小值相关联):

list_min([L|Ls], Min) :- list_min(Ls, L, Min).

list_min([], Min, Min).
list_min([L|Ls], Min0, Min) :-
    Min1 is min(L, Min0),
    list_min(Ls, Min1, Min).

这种模式称为 fold (从左侧开始),我们可以使用`foldl / 4:

等效地编写它
list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).

min_(A, B, Min) :- Min is min(A, B).

示例查询:

?- list_min([1,0,2], Min).
Min = 0.

请注意,这不是真正的关系,并且由于使用了低级算术而无法在所有方向上使用。例如,如果我们尝试在另一个方向上使用它,我们得到:

?- list_min([X,Y], 3).
ERROR: is/2: Arguments are not sufficiently instantiated

要使其成为真正的解决方案,请使用约束,例如。例如,对于整数的解决方案:

:- use_module(library(clpfd)).

list_min([L|Ls], Min) :- foldl(min_, Ls, L, Min).

min_(A, B, Min) :- Min #= min(A, B).

这适用于所有方向:

?- list_min([X,Y], 3).
X in 3..sup,
3#=min(Y, X),
Y in 3..sup.

答案 2 :(得分:3)

语法错误是,因为Prolog中的数量少于或等于=&lt;,不是&lt; =。

我认为这种方法可行,但你真的应该避免;在一个条款中。把它分成两个条款。

另外我认为你想在递归中做[X | Tail]而不是[X,Tail]

答案 3 :(得分:2)

min([H|T], Min) :- min(T, H, Min).

min([], Min, Min).
min([H|T], Min, Min1) :-
  (   H < Min
  ->  min(T, H, Min1)
  ;   min(T, Min, Min1) ).