如何检查列表中的哪些项目满足特定条件?

How to check which items on the list meet certain condition?

如何制作一个名为 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).

您的代码中需要修复的一些问题:

  • 第三个参数是[_|_],也就是说结果是自由变量……没有意义。您需要两种情况:一种是 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]

以下是使用 的方法, 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)以下元谓词的术语:maplist/3tfilter/3tfiltermap/4tchoose/3。当然,最后我们只需要一个---但这不应该阻止我们探索我们拥有的各种选择!

#1:基于tfilter/3 and maplist/3

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

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

#2:基于tfiltermap/4

在这里,我们使用与之前完全相同的 lambda 表达式,但我们通过 他们 both 到元谓词 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].

完成!

那么...底线是什么

  • 许多元谓词都是通用的,可以用在很多类似于这里的情况中。
  • 实施这些元谓词是一次性的工作,可以迅速分期偿还。
  • 许多元谓词处理 "recursive part",使您能够专注于实际工作。
  • 通常,对于元谓词(与常规谓词一样),"there's more than one way to do things"。
    • 根据具体情况,使用特定的元谓词可能比使用另一个更好,反之亦然。
    • 对于这个问题,我认为实现#3(使用 tchoose/3 的那个)是最好的。