如何检查列表中的哪些项目符合一定条件?

时间:2015-06-18 19:59:44

标签: prolog

如何创建一个名为busLineLonger的函数,它接收至少两个参数来决定总线是否更长?

*/This is how it works*/
* busStops(number_of_the_bus,number_of_stops)*/

/*?- busLineLonger([busStops(1,7),busStops(2,4),busStops(3,6)],5,WHICH).
* WHICH = [1,3].

仅使用比较性内容,例如@> < @ / == @。 对不起我的英文

编辑... 到目前为止,我已经想到了像这样的东西

busLineLonger([busStops(A,B)|R],N,[_|_]):-
   N@>B,
   busLineLonger(R,N,A).

2 个答案:

答案 0 :(得分:2)

以下是使用进行操作的方法, reified test predicates, 和lambda expressions

:- use_module(library(lambda)).

首先,我们像这样定义具体化的测试谓词(>)/3

>(X,Y,Truth) :- (X > Y -> Truth=true ; Truth=false).

接下来,我们根据以下元素定义三个 busLineLonger/3(名为busLineLonger1/3busLineLonger2/3busLineLonger3/3)的不同实现-predicates:maplist/3tfilter/3tfiltermap/4tchoose/3。当然,最终我们只需要一个 ---但这不应该阻止我们探索我们的各种选择!

#1:基于tfilter/3maplist/3

执行两个单独的步骤:  1.选择关注的项目。  2.将这些项目投射到感兴趣的数据中。

busLineLonger1(Ls0,N,IDs) :-
    tfilter(\busStops(_,L)^(L>N), Ls0,Ls1),
    maplist(\busStops(Id,_)^Id^true, Ls1, IDs).

#2:基于tfiltermap/4

在这里,我们使用与以前完全相同的lambda表达式,但是我们通过了 他们两者到元谓词tfiltermap/4。这样做有助于减少 节省一些资源。

busLineLonger2(Ls,N,IDs) :-
    tfiltermap(\busStops(_,L)^(L>N), \busStops(Id,_)^Id^true, Ls,IDs).

以下是tfiltermap/4的实施方式:

:- meta_predicate tfiltermap(2,2,?,?).
tfiltermap(Filter_2,Map_2,Xs,Ys) :-
   list_tfilter_map_list(Xs,Filter_2,Map_2,Ys).

:- meta_predicate list_tfilter_map_list(?,2,2,?).
list_tfilter_map_list([],_,_,[]).
list_tfilter_map_list([X|Xs],Filter_2,Map_2,Ys1) :-
   if_(call(Filter_2,X), (call(Map_2,X,Y),Ys1=[Y|Ys0]), Ys1=Ys0),
   list_tfilter_map_list(Xs,Filter_2,Map_2,Ys0).

#3:基于tchoose/3

这里我们不使用两个单独的lambda表达式,而是一个组合的表达式。

busLineLonger3(Ls,N,IDs) :-
    tchoose(\busStops(Id,L)^Id^(L>N), Ls,IDs).

以下是tchoose/3的实施方式:

:- meta_predicate tchoose(3,?,?).
tchoose(P_3,Xs,Ys) :-
   list_tchoose_list(Xs,P_3,Ys).

:- meta_predicate list_tchoose_list(?,3,?).
list_tchoose_list([],_,[]).
list_tchoose_list([X|Xs],P_3,Ys1) :-
   if_(call(P_3,X,Y), Ys1=[Y|Ys0], Ys1=Ys0),
   list_tchoose_list(Xs,P_3,Ys0).

让我们看看他们的行动!

?- Xs = [busStops(1,7),busStops(2,4),busStops(3,6)], busLineLonger1(Xs,5,Zs).
Xs = [busStops(1, 7), busStops(2, 4), busStops(3, 6)],
Zs = [1, 3].

?- Xs = [busStops(1,7),busStops(2,4),busStops(3,6)], busLineLonger2(Xs,5,Zs).
Xs = [busStops(1, 7), busStops(2, 4), busStops(3, 6)],
Zs = [1, 3].

?- Xs = [busStops(1,7),busStops(2,4),busStops(3,6)], busLineLonger3(Xs,5,Zs).
Xs = [busStops(1, 7), busStops(2, 4), busStops(3, 6)],
Zs = [1, 3].

完成!

那么...... 底线是什么?

  • 许多元谓词都是通用的,并且可以在很多类似于这里的场景中使用。
  • 实施这些元谓词是一次性的努力,可以快速摊销。
  • 许多元谓词处理"递归部分",这使您能够专注于实际工作。
  • 通常,使用元谓词(与常规谓词一样),"有多种方法可以做事情"。
    • 根据具体情况,使用特定的元谓词可能比使用另一个元谓词更好,反之亦然。
    • 对于这个问题,我认为,实施#3(使用tchoose/3的那个)是最好的。

答案 1 :(得分:0)

您的代码中需要修复的一些事项:

  • 第三个参数是[_|_],结果是自由变量......没有意义。您需要两种情况:一种情况B大于N并且您包含结果; B小于或等于N的另一个,并且您不包含该结果。
  • 缺少基本情况。总线列表为空时的结果是什么?

可能的解决方案:

busLineLonger([],_,[]).
busLineLonger([busStops(A,B)|R],N,[A|S]) :- B>N, busLineLonger(R,N,S).
busLineLonger([busStops(_,B)|R],N,S) :- B=<N, busLineLonger(R,N,S).
?- busLineLonger([busStops(1,7),busStops(2,4),busStops(3,6)],5,WHICH).
WHICH = [1, 3]