作为一个Prolog新手,我尝试定义一个谓词filter_min/2
,它使用两个列表来确定第二个列表是否与第一个列表相同,但是删除了所有出现的最小值。
带有预期结果的示例查询:
?- filter_min([3,2,7,8], N).
N = [3,7,8].
?- filter_min([3,2,7,8], [3,7,8]).
true.
我试过,但我总是得到相同的结果:false
。我不知道问题是什么。我需要帮助!
这是我的代码:
filter_min(X,Y) :-
X == [],
write("ERROR: List parameter is empty!"),
!;
min_list(X,Z),
filter(X,Y,Z).
filter([],[],0).
filter([H1|T1],[H2|T2],Z) :-
\+ number(H1),
write("ERROR: List parameter contains a non-number element"),
!;
H1 \= Z -> H2 is H1, filter(T1,T2,Z);
filter(T1,T2,Z).
答案 0 :(得分:4)
您的代码存在一些问题:
filter([],[],0).
将不会统一,这不是您想要的。无论结束递归的最小值,都希望它统一起来。filter([H1|T1],[H2|T2],Z)
及其正文的方式将使两个列表始终具有相同数量的元素,而实际上第二个列表应至少少一个。 filter/3
的正确实施如下:
filter([],[],_).
filter([H1|T1],L2,Z):-
\+ number(H1),
write("ERROR: List parameter contains a non-number element"),
!;
H1 \= Z -> filter(T1,T2,Z), L2 = [H1|T2];
filter(T1,L2,Z).
答案 1 :(得分:3)
提供赏金......
...对于一个纯粹的解决方案,它终止于(某些)第一个和第二个参数的长度都不知道的情况。
这是一个处理整数值的候选实现,构建于clpfd:
:- use_module(library(clpfd)).
filter_min(Xs,Ys) :-
filter_min_picked_gt(Xs,_,false,Ys).
filter_min_picked_gt([] ,_,true ,[]).
filter_min_picked_gt([Z|Xs],M,Picked,[Z|Zs]) :-
Z #> M,
filter_min_picked_gt(Xs,M,Picked,Zs).
filter_min_picked_gt([M|Xs],M,_,Zs) :-
filter_min_picked_gt(Xs,M,true,Zs).
一些示例查询:
?- filter_min([3,2,7,8],[3,7,8]). true ; false. % correct, but leaves choicepoint ?- filter_min([3,2,7,8],Zs). Zs = [3,7,8] ; false. % correct, but leaves choicepoint
现在,即使两个列表长度都未知,一些查询也会终止:
?- filter_min([2,1|_],[1|_]).
false. % terminates
?- filter_min([1,2|_],[3,2|_]).
false. % terminates
请注意,在逻辑错误的情况下,实现不会总是有限地失败(终止):
?- filter_min([1,2|_],[2,1|_]). % does _not_ terminate
答案 2 :(得分:2)
首先,我们可以使用谓词list_minnum/2
获取最小数字:
?- list_minnum([3,2,7,8],M).
M = 2.
我们可以像这样定义list_minnum/2
:
list_minnum([E|Es],M) :-
V is E,
list_minnum0_minnum(Es,V,M).
list_minnum0_minnum([],M,M).
list_minnum0_minnum([E|Es],M0,M) :-
M1 is min(E,M0),
list_minnum0_minnum(Es,M1,M).
为了完整起见,这里有超级相似的list_maxnum/2
:
list_maxnum([E|Es],M) :-
V is E,
list_maxnum0_maxnum(Es,V,M).
list_maxnum0_maxnum([],M,M).
list_maxnum0_maxnum([E|Es],M0,M) :-
M1 is max(E,M0),
list_maxnum0_maxnum(Es,M1,M).
接下来,我们使用meta-predicate tfilter/3
与dif/3
一起排除{strong>所有出现的M
:
?- M=2, tfilter(dif(M),[2,3,2,7,2,8,2],Xs).
Xs = [3,7,8].
将两个步骤放在一起并定义min_excluded/2
:
min_excluded(Xs,Ys) :-
list_minnum(Xs,M),
tfilter(dif(M),Xs,Ys).
让我们运行一些查询!
?- min_excluded([3,2,7,8],Xs).
Xs = [3,7,8].
?- min_excluded([3,2,7,8,2],Xs).
Xs = [3,7,8].
答案 3 :(得分:2)
对于Prolog新手,最好从基础开始。当第一个参数完全实例化时,以下工作正常,第二个参数是未实例化的变量,在输入列表的一次传递中计算结果。
% remmin( +From, -Result).
% remmin([],[]). % no min elem to remove from empty list
remmin([A|B], R):-
remmin(B, A, [A], [], R). % remove A from B to get R, keeping [A]
% in case a smaller elem will be found
remmin([C|B], A, Rev, Rem, R):-
C > A -> remmin(B, A, [C|Rev], [C|Rem], R) ;
C==A -> remmin(B, A, [C|Rev], Rem, R) ;
C < A -> remmin(B, C, [C|Rev], Rev, R).
remmin([], _, _, Rem, R) :- reverse(Rem, R).