在Prolog的混合列表中找到最小值

时间:2017-03-19 22:16:23

标签: prolog

我是prolog的新手,我只是在学习列表而且我遇到了this question。答案适用于整数列表。

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

如何更改此代码以从混合列表中获取最小的int?

这个

sint([a,b,3,2,1],S)

应该给出答案:

S=1

3 个答案:

答案 0 :(得分:2)

你可以忽略这个问题,将比较运算符(>)/ 2(实际上是二进制内置谓词)更改为更通用的(@>)/ 2:

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

?- minimo([a,b,3,2,1],S).
S = 1.

答案 1 :(得分:1)

您可以编写一个谓词,该谓词返回带有数字的列表并使用上面的minimo / 2谓词:

only_numbers([],[]).
only_numbers([H|T],[H|T1]):-integer(H),only_numbers(T,T1).
only_numbers([H|T],L):- \+integer(H),only_numbers(T,L).

sint(L,S):-only_numbers(L,L1),minimo(L1,S).

答案 2 :(得分:1)

首先,我不认为提议的实现非常优雅:在这里,他们通过每次构建一个新列表来传递最小的找到元素。使用附加参数(我们称之为累加器)通常是要走的路(也可能更有效)。

为了解决这个问题,我们首先必须找到一个整数。我们可以这样做:

sint([H|T],R) :-
    integer(H),
    !,
    sint(T,H,R).
sint([_|T],R) :-
    sint(T,R).

所以我们在这里检查 head H是否为integer/1。如果是这种情况,我们会调用谓词sint/3(不要与sint/2混淆)。否则,我们会使用列表的 tail sint/2递归调用T

现在我们仍然需要定义sint/3。如果我们到达列表[]的末尾,我们只返回到目前为止找到的最小值:

sint([],R,R).

否则有两种情况:

  • head H是一个整数,小于到目前为止找到的元素,在这种情况下,我们执行递归,将head作为新的当前最小值:

    sint([H|T],M,R):
        integer(H),
        H < M,
        !,
        sint(T,H,R).
    
  • 否则,我们只是忽略头部,并使用尾部T执行递归。

    sint([_|T],M,R) :-
        sint(T,M,R).
    

我们可以将递归子句放在if-then-else结构中。与之前定义的谓词一起,完整的程序就是:

sint([H|T],R) :-
    integer(H),
    !,
    sint(T,H,R).
sint([_|T],R) :-
    sint(T,R).

sint([],R,R).
sint([H|T],M,R):
    (
     (integer(H),H < M)
     -> sint(T,H,R)
     ;  sint(T,M,R)
    ).

这种方法的优点是过滤比较(以获得最小值)是同时完成的,所以我们只在列表上迭代一次。这通常会导致性能提升,因为&#34;控制结构&#34;只执行一次:更多是在迭代中完成,但我们只迭代一次。

我们可以通过过滤器泛型来概括该方法:

filter_minimum(Filter,[H|T],R) :-
    Goal =.. [Filter,H],
    call(Goal),
    !,
    filter_minimum(Filter,T,H,R).
filter_minimum(Filter,[_|T],R) :-
    filter_minimum(Filter,T,R).

filter_minimum(_,[],R,R).
filter_minimum(Filter,[H|T],M,R) :-
    Goal =.. [Filter,H],
    (
     (call(Goal),H < M)
     -> filter_minimum(Filter,T,H,R)
     ;  filter_minimum(Filter,T,M,R)
    ).

然后你可以用:

来调用它
filter_minimum(integer,[a,b,3,2,1],R).

使用integer/1进行过滤并计算最小值。