我想在Prolog中做出一个反向谓词(N,结果)。
例如:
我必须使用尾递归。我可以使用*,+, - 和divmod / 4以及所有。我不能使用列表。
我可以反转一个数字< 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.
我可以帮忙吗?
提前谢谢你。
答案 0 :(得分:3)
我建议使用CLP(FD),因为它提供了整数运算的声明性推理,并且很多Prolog系统都提供了它。关于数字反转,我建议你看看条目A004086 in The On-Line Encyclopedia of Integer Sequences。在 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 ; % <- 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 ;
.
.
.
要使用上面的查询获取实际数字,您必须限制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.
答案 1 :(得分:0)
如果由于某种原因您不想要基于约束的解决方案,或者如果您使用不支持约束的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.