Recursion 如何使用尾部递归在Prolog中反转整数?

Recursion 如何使用尾部递归在Prolog中反转整数?,recursion,prolog,integer,reverse,tail-recursion,Recursion,Prolog,Integer,Reverse,Tail Recursion,我想在Prolog中做一个谓词反转(N,Result)。 例如: 相反(12345,结果) 结果=54321 我必须使用尾部递归。我可以使用*、+、-和divmod/4,仅此而已。我不能使用list 我可以反转小于100的数字,但我不知道如何完成我的代码,我无法正确地反转大于100的整数 reverse(N,N):- N <10, N>0. reverse(N,Result):- N > 9, iter(N,0,Result). iter

我想在Prolog中做一个谓词反转(N,Result)。

例如:

  • 相反(12345,结果)
  • 结果=54321
我必须使用尾部递归。我可以使用*、+、-和divmod/4,仅此而已。我不能使用list

我可以反转小于100的数字,但我不知道如何完成我的代码,我无法正确地反转大于100的整数

reverse(N,N):-
    N <10,
    N>0.

reverse(N,Result):-
    N > 9,
    iter(N,0,Result).

iter(N,Ac,Result):-
    N  < 100, !,
    divmod(N,10,Q,R),
    R1 is R*10,
    Result is Q + R1.
反向(N,N):-
n0。
反向(N,结果):-
N>9,
iter(N,0,结果)。
国际热核实验堆(N,Ac,结果):-
N<100!,
divmod(N,10,Q,R),
R1是R*10,
结果是Q+R1。
能帮我点忙吗

提前感谢您。

我建议使用,因为它提供了对整数算术的声明式推理,许多Prolog系统都提供了它。关于数字反转,我建议你看一下输入。在标题为“公式”的段落中,您将发现以下公式:

a(n) = d(n,0) with d(n,r) = if n=0 then r else d(floor(n/10),r*10+(n mod 10))
可以通过为反转的数字添加额外的参数将其转换为谓词。首先,让我们给它一个好的声明性名称,比如说
digits\u reversed/2
。然后,可以使用
#>/2
#=/2
(/)/2
+/2
mod/2
和尾部递归来表示关系:

:- use_module(library(clpfd)).

digits_reversed(N,X) :-
   digits_reversed_(N,X,0).

digits_reversed_(0,R,R).
digits_reversed_(N,X,R) :-
   N #> 0,
   N0 #= N/10,
   R1 #= R*10 + (N mod 10),
   digits_reversed_(N0,X,R1).
注意,在上述公式中,
digits\u reversed/2
对应于
a(n)
digits\u reversed\u/3
对应于
d(n,r)
。现在,让我们使用您文章中的示例查询谓词:

?- digits_reversed(12345,R).
R = 54321 ;
false.
谓词也可以用于另一个方向,即询问已反转的数字是多少以获得54321?但是,由于省略了数字的前导零,因此一个反向数字具有无穷多个原始数字:

?- digits_reversed(N,54321).
N = 12345 ;
N = 123450 ;
N = 1234500 ;
N = 12345000 ;
N = 123450000 ;
N = 1234500000 ;
N = 12345000000 ;
N = 123450000000 ;
.
.
.
即使是最一般的查询也会产生解决方案,但对于超过一位数的数字,您也会得到剩余目标:

?- digits_reversed(N,R).
N = R, R = 0 ;              % <- zero
N = R,
R in 1..9 ;                 % <- other one-digit numbers
N in 10..99,                % <- numbers with two digits
N mod 10#=_G3123,
N/10#=_G3135,
_G3123 in 0..9,
_G3123*10#=_G3159,
_G3159 in 0..90,
_G3159+_G3135#=R,
_G3135 in 1..9,
R in 1..99 ;
N in 100..999,              % <- numbers with three digits
N mod 10#=_G4782,
N/10#=_G4794,
_G4782 in 0..9,
_G4782*10#=_G4818,
_G4818 in 0..90,
_G4818+_G4845#=_G4842,
_G4845 in 0..9,
_G4794 mod 10#=_G4845,
_G4794 in 10..99,
_G4794/10#=_G4890,
_G4890 in 1..9,
_G4916+_G4890#=R,
_G4916 in 0..990,
_G4842*10#=_G4916,
_G4842 in 0..99,
R in 1..999 ;
.
.
.

如果出于某种原因,您不需要基于约束的解决方案,或者如果您使用的Prolog系统不支持约束,则另一种解决方案是:

reverse_digits(N, M) :-
    (   integer(N) ->
        reverse_digits(N, 0, M)
    ;   integer(M),
        reverse_digits(M, 0, N)
    ).

reverse_digits(0, M, M) :- !.
reverse_digits(N, M0, M) :-
    N > 0,
    R is N div 10,
    M1 is M0 * 10 + N mod 10,
    reverse_digits(R, M1, M).
此解决方案可与绑定到整数的任一参数一起使用,且不会留下虚假的选择点:

?- reverse_digits(12345, M).
M = 54321.

?- reverse_digits(N, 12345).
N = 54321.

?- reverse_digits(12345, 54321).
true.
但请注意,与基于约束的解决方案不同,此解决方案不能用作满足以下关系的整数对生成器:

?- reverse_digits(N, M).
false.

我试着打招呼,但我无法编辑我的post@Yashrod您是否尝试将数字拆分为数字列表,然后反转列表,然后创建反转的数字?@AntonDanilov对不起,我应该说我不能使用列表,我编辑了我的帖子。为什么
不反转(N,N)
如果
N>=0
而不仅仅是
N>0
,请确认为真。谢谢您抽出时间。这对我帮助很大。谢谢你的帮助。
?- reverse_digits(N, M).
false.