使用( if -> then ; else )
您可能正在寻找的控制结构是( if -> then ; else )。
警告:您可能应该交换前两个参数的顺序:
lessthan_if([], _, []).
lessthan_if([X|Xs], Y, Zs) :-
( X < Y
-> Zs = [X|Zs1]
; Zs = Zs1
),
lessthan_if(Xs, Y, Zs1).
然而,如果你正在编写真正的代码,你几乎肯定应该使用library(apply) 中的谓词之一,例如include/3,如suggested by @CapelliC:
?- include(>(3), [1,2,3], R).
R = [1, 2].
?- include(>(4), [1,2,3], R).
R = [1, 2, 3].
?- include(<(2), [1,2,3], R).
R = [3].
如果您想知道如何解决此类问题,请参阅the implementation of include/3。你会注意到上面的lessthan/3 只不过是库中更通用的include/3 的特化(应用):include/3 将重新排列参数并使用( if -> then ; else )。
“声明式”解决方案
或者,一个更少“程序性”和更多“声明性”的谓词:
lessthan_decl([], _, []).
lessthan_decl([X|Xs], Y, [X|Zs]) :- X < Y,
lessthan_decl(Xs, Y, Zs).
lessthan_decl([X|Xs], Y, Zs) :- X >= Y,
lessthan_decl(Xs, Y, Zs).
(lessthan_if/3 和 lessthan_decl/3 几乎与 solutions by Nicholas Carey 相同,只是参数的顺序不同。)
不利的一面是,lessthan_decl/3 留下了选择点。但是,对于通用的、可读的解决方案来说,这是一个很好的起点。我们需要两个代码转换:
- 将算术比较
< 和 >= 替换为 CLP(FD) 约束:#< 和 #>=;
- 使用 DCG 规则去除定义中的参数。
您将到达solution by lurker。
另一种方法
Prolog 中最通用的比较谓词是compare/3。使用它的一个常见模式是显式枚举Order 的三个可能值:
lessthan_compare([], _, []).
lessthan_compare([H|T], X, R) :-
compare(Order, H, X),
lessthan_compare_1(Order, H, T, X, R).
lessthan_compare_1(<, H, T, X, [H|R]) :-
lessthan_compare(T, X, R).
lessthan_compare_1(=, _, T, X, R) :-
lessthan_compare(T, X, R).
lessthan_compare_1(>, _, T, X, R) :-
lessthan_compare(T, X, R).
(与任何其他解决方案相比,这个解决方案适用于任何项,而不仅仅是整数或算术表达式。)
将compare/3 替换为zcompare/3:
:- use_module(library(clpfd)).
lessthan_clpfd([], _, []).
lessthan_clpfd([H|T], X, R) :-
zcompare(ZOrder, H, X),
lessthan_clpfd_1(ZOrder, H, T, X, R).
lessthan_clpfd_1(<, H, T, X, [H|R]) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(=, _, T, X, R) :-
lessthan_clpfd(T, X, R).
lessthan_clpfd_1(>, _, T, X, R) :-
lessthan_clpfd(T, X, R).
这绝对是比任何其他解决方案更多的代码,但它不会留下不必要的选择点:
?- lessthan_clpfd(3, [1,3,2], Xs).
Xs = [1, 2]. % no dangling choice points!
在其他情况下,它的行为与 lurker 的 DCG 解决方案一样:
?- lessthan_clpfd(X, [1,3,2], Xs).
Xs = [1, 3, 2],
X in 4..sup ;
X = 3,
Xs = [1, 2] ;
X = 2,
Xs = [1] ;
X = 1,
Xs = [] .
?- lessthan_clpfd(X, [1,3,2], Xs), X = 3. %
X = 3,
Xs = [1, 2] ; % no error!
false.
?- lessthan_clpfd([1,3,2], X, R), R = [1, 2].
X = 3,
R = [1, 2] ;
false.
除非您需要这种通用方法,否则include(>(X), List, Result) 就足够了。