我有一个这样的问题:找到一个列表中的所有元素,使得除它之外的所有元素都是奇数。
例如
?- find([20,1,2,3,4,5,6,7,8,10], L).
L = [20, 2, 4, 6]
通常在其他语言中,我会遍历列表并检查条件,但在这种情况下我不知道如何在 Prolog 中“思考”。我应该如何处理这个?
我有一个这样的问题:找到一个列表中的所有元素,使得除它之外的所有元素都是奇数。
例如
?- find([20,1,2,3,4,5,6,7,8,10], L).
L = [20, 2, 4, 6]
通常在其他语言中,我会遍历列表并检查条件,但在这种情况下我不知道如何在 Prolog 中“思考”。我应该如何处理这个?
考虑一对头元素访问列表:
find([A,B|R], [A|T]) :-
is_odd(B),
... etc etc
您显然需要添加基本递归情况以及必须丢弃 A 的情况。
编辑:基于 CapelliCs 建议的更好解决方案(这使用isodd
下面的谓词):
% if N0 and N2 are odd, cut, add N1 to the result and recurse
ff([N0,N1,N2|T], [N1|R]) :- isodd(N0), isodd(N2), !, ff([N1,N2|T], R).
% for any other case where the list has at least three members, cut and recurse
ff([_,N1,N2|T], R) :- !, ff([N1,N2|T], R).
% this is reached if the list has less that three members - we're done
ff(_, []).
% append and prepend '1' to the list to deal with the edges, call ff.
find(L, R) :- append(L, [1], L1), ff([1|L], R).
我的旧解决方案使用额外的参数跟踪前两个值:
% isodd(+N)
% helper predicate that succeds for odd numbers.
isodd(N) :- mod(N, 2) =:= 1.
% find(+I, +N1, +N2, +R, -L)
% find/5 is the predicate doing the actual work.
% I is the input list, N1 and N2 are the numbers before the current one,
% R is the intermediate result list and L the result.
% we're done if the input list is empty
find([], _, _, R, R) :- !.
% check if N0 and N2 are odd to see if N1 should be appended to the list.
% if yes, do a cut, append N1 to the result and recurse.
find([N0|T], N1, N2, R, L) :-
isodd(N0), isodd(N2), !,
append(R, [N1], R1), find(T, N0, N1, R1, L).
% if N0 and N2 are not odd (and thus the cut in the previous clause isn't
% reached) just continue the recursion.
find([N0|T], N1, _, R, L) :- find(T, N0, N1, R, L).
% find(+I, -L)
% this predicate is the entry point - initialize the result list and the first
% values for N1 and N2, and append 1 to the input list so we don't need an extra
% predicate for dealing with the last item.
find(I, L) :- append(I, [1], I1), find(I1, 1, 0, [], L).