使用Prolog在列表中查找具有最低第二个参数的术语

时间:2015-07-20 09:25:51

标签: prolog

我有一个这样的清单:

L = [range(2,3), range(5,6), range(10,9), range(-2,-30), range(-5,-30)]

现在,我需要将术语range(-5,-30)作为此列表的第一个元素,因为它是具有最低Y的术语,在2个术语具有最低Y的情况下,我会选择X最低的那个。

我不知道如何用Prolog做这件事,我尝试了类似的事情:

find_n_make_first([F,S|T]) :-
 F =.. [_,Fx,Fy],
 S =.. [_,Sx,Sy],
 (   Sy<Fy ->
 find_n_make_first([S,F|T])
 ;   Fy<Sy ->
 find_n_make_first([F,S|T])
 ;   Fy = Sy ->
 (   Sx<Fx ->
 find_n_make_first([S,F|T])
 ;   Fx<Sx ->
 find_n_make_first([F,S|T])
 )
 ).

但它没有用。

1 个答案:

答案 0 :(得分:3)

实际上,您的第一个问题是要了解如何使用这样的定义。始终以想象开始,您已经有了一个有效的定义。你将在那里了解关系中最重要的部分:关系中没有隐含的“回归值”。您需要单独定义它们。所以在你的情况下,这将是:

?- list_sortedby2([range(2,3),range(10,9),range(-2,-30),range(-5,-30)], Us).
Us = [range(-5,-30),range(-2,-30),range(2,3),range(10,9)].

只有然后开始定义它!

:- use_module(library(lambda)).

list_sortedby2(Ts, Us) :-
   must_be_ground(Ts),
   maplist(\T^(A2+T)^arg(2,T,A2), Ts, A2Ts), % or map1(Ts, A2Ts)
   sort(A2Ts, A2Us),
   maplist(\ (_+U)^U^true, A2Us, Us).        % or map2(A2Us, Us)

must_be_ground(Ss) :-
   ( ground(Ss) -> true
   ; throw(error(instantiation_error,_))
   ).

代替maplist/3和λ,您也可以手动编写:

map1([], []).
map1([T|Ts], [A2+T|A2Ts]) :-
   arg(2, T, A2),
   map1(Ts, A2Ts).

map2([], []).
map2([_+U|A2Us], [U|Us]) :-
   map2(A2Us, Us).

通过事后的想法,还有其他的东西:更好地用arg(2, T, A2)替换目标( T = range(_, A2) ),因为你只对结构range/2感兴趣。以这种方式,list_sortedby2([f(1,2)], Us)失败,这是一种处理意外情况的更安全的方法。 (产生类型错误会更安全,但至少它不会成功。)