我在Prolog中编写了一个尾递归谓词,它在列表A
中输出B
和K
之间的整数。我已经使用过"反向"将数字输入正确的顺序:
numbers(A,B,K) :- numbers(A,B,[],K).
numbers(Y,Y,X,K) :- !, reverse([Y|X],K).
numbers(A,B,X,K) :- A<B, C is A+1, numbers(C,B,[A|X],K).
查询:
?- numbers(3,6, K).
K=[3,4,5,6]
一切正常。我现在想要做的是,我只想在列表A
中的B
和K
之间使用奇数。我怎样才能做到这一点?提前谢谢!
答案 0 :(得分:3)
首先,我会尽量避免使用reverse/2
。如果您有这样的解决方案,通常表明有更好的方法可以更直接地获得答案。并非总是如此,但最常见。 reverse/2
可能是Prolog在使用剪辑后第二个最喜欢的创可贴。 :)
在许多问题中,需要辅助蓄电池。在这种特殊情况下,事实并非如此。此外,当涉及整数时,我倾向于使用CLP(FD)操作,因为它是整数推理的更多关系方法。但是,如果您愿意,可以使用下面的解决方案is/2
等。它只是不会像一般人一样。
numbers(S, E, []) :- S #> E. % null case
numbers(X, X, [X]).
numbers(S, E, [S|T]) :-
S #< E,
S1 #= S + 1,
numbers(S1, E, T).
| ?- numbers(3, 8, L).
L = [3,4,5,6,7,8] ? ;
no
| ?- numbers(A, B, [2,3,4,5]).
A = 2
B = 5 ? ;
no
| ?-
此解决方案避免reverse/2
并且是尾递归。
要为奇数整数更新它,首先想到的是我们可以通过添加2而不是1来轻松地修改上面的所有其他数字:
every_other_number(S, E, []) :- S #> E.
every_other_number(X, X, [X]).
every_other_number(S, E, [S|T]) :-
S #< E,
S1 #= S + 2,
every_other_number(S1, E, T).
| ?- every_other_number(3, 7, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(3, 8, L).
L = [3,5,7] ? ;
no
| ?- every_other_number(4, 8, L).
L = [4,6,8] ? ;
no
| ?-
然后我们可以通过创建一个初始谓词来确定奇数,以确保第一个值为奇数并调用every_other_number/3
的条件:
odd_numbers(S, E, L) :-
S rem 2 #= 1,
every_other_number(S, E, L).
odd_numbers(S, E, L) :-
S rem 2 #= 0,
S1 #= S + 1,
every_other_number(S1, E, L).
| ?- odd_numbers(2, 8, L).
L = [3,5,7] ? ;
no
| ?- odd_numbers(2, 9, L).
L = [3,5,7,9] ? ;
no
| ?- odd_numbers(3, 8, L).
L = [3,5,7] ? ;
no
| ?-
答案 1 :(得分:2)
这可以是一个解决方案,使用mod/2
运算符。
numbers(A,B,K) :-
B1 is B+1,
numbers(A,B1,[],K).
numbers(Y,Y1,X,K) :-
Y = Y1,
reverse(X,K).
numbers(A,B,X,K) :-
A<B,
C is A+1,
C1 is mod(C,2),
(C1 = 0 ->
numbers(C,B,[A|X],K)
; numbers(C,B,X,K)).
答案 2 :(得分:1)
另一种可能性是使用DCG:
numbers(A,B,K) :-
phrase(odd(A,B), K).
odd(A,B) --> {A > B, !}, [].
odd(A,B) --> {A mod2 =:= 0, !, C is A+1}, odd(C,B).
odd(A,B) --> {C is A+2}, [A], odd(C, B).