我建议使用
CLP(FD),因为它提供了整数算术的声明性推理,许多Prolog系统都提供它。关于数字反转,我建议您查看
The On-Line Encyclopedia of Integer Sequences中的条目A004086。在标题为
FORMULA的段落中,您将找到以下公式中的一些:
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_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_reversed/2
对应于上述公式中的
a(n)
,
digits_reversed_/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 ;
N = R,
R in 1..9 ;
N in 10..99,
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,
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 ;
.
.
.
为了获得上述查询的实际数字,您需要限制
N
的范围,并在谓词发布算术约束后对其进行标记。
?- N in 10..20, digits_reversed(N,R), label([N]).
N = 10,
R = 1 ;
N = R, R = 11 ;
N = 12,
R = 21 ;
N = 13,
R = 31 ;
N = 14,
R = 41 ;
N = 15,
R = 51 ;
N = 16,
R = 61 ;
N = 17,
R = 71 ;
N = 18,
R = 81 ;
N = 19,
R = 91 ;
N = 20,
R = 2 ;
false.
N >= 0
而不仅仅是N > 0
,为什么reverse(N, N)
不会成立呢? - lurker