prolog中的尾递归程序,它在列表中输出奇数

时间:2017-12-09 11:11:30

标签: prolog tail-recursion

我在Prolog中编写了一个尾递归谓词,它在列表A中输出BK之间的整数。我已经使用过"反向"将数字输入正确的顺序:

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中的BK之间使用奇数。我怎样才能做到这一点?提前谢谢!

3 个答案:

答案 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).