我正在尝试在Prolog(SWI-Prolog)中生成所有自然数字对,
即。正式有一个函数f(X,Y)
,这样:
使用未绑定变量f(X,Y)
,X
调用Y
后,对于每对自然数(m,n),存在一个n0,这样在按分号n0次后,Prolog将返回(X,Y)=(m,n)
。
我希望使用Cantor's pairing function来编写函数。简而言之,它按如下方式枚举对:(0,0),(1,0),(0,1),(2,0),(1,1),(0,2),(3,0) ),(2,1),(1,2),(0,3),(4,0)......
我表达如下:
gen(0,0). % 'root'
gen(M,0) :- gen(0, X), M is X+1. % 'jump to the previous diagonal'
gen(M,N) :- gen(X, Y), M is X-1, N is Y+1, N > 0. % 'a step inside a diagonal'
然而,由于Prolog搜索实际上是如何工作的,这最终导致第二个规则反复调用自身,ad infinitem,最终由于堆栈空间耗尽而崩溃(在此之前它返回的唯一结果是(0,0)和(1,0),然后它被卡住,在'0为0 + 1'时反复失败第二条规则。)
您是否有任何想法如何使这个或任何其他优雅的方法有效?
谢谢。
根据接受的答案(谢谢!),我按照预期编写了以下代码:
range(Min, _, Min).
range(Min, Max, Val) :- NewMin is Min+1, Max >= NewMin, range(NewMin, Max, Val).
natnum(0).
natnum(N) :-
natnum(N0),
N is N0 + 1.
gen(A,B) :-
natnum(N),
range(0, N, B),
A is N - B.
使用时:
?- gen(X,Y).
X = 0,
Y = 0 ;
X = 1,
Y = 0 ;
X = 0,
Y = 1 ;
X = 2,
Y = 0 ;
X = 1,
Y = 1 ;
X = 0,
Y = 2 ;
X = 3,
Y = 0
and so on...
答案 0 :(得分:6)
我给你一个开始:
让我们从一个谓词开始,该谓词在回溯中创建所有自然数,并为每个解决方案产生单这样的数字:
natnum(0). natnum(N) :- N #= N0 + 1, natnum(N0).
示例查询:
?- natnum(N). N = 0 ; N = 1 ; N = 2 ; N = 3 ; etc.
然后,我们观察到我们可以通过限制每对的 sum 来生成这样的对而不会陷入无限循环。例如:
pair(A-B) :- natnum(N), N #>= A + B, A #>= 0, B #>= 0, label([A,B]).
示例查询:
?- pair(P). P = 0-0 ; P = 0-0 ; P = 0-1 ; P = 1-0 ; P = 0-0 ; P = 0-1 ; P = 0-2 ; P = 1-0 ; P = 1-1 ; P = 2-0 ; P = 0-0 ; P = 0-1 ; P = 0-2 ; P = 0-3 ; P = 1-0 ; P = 1-1 .
这显然不完美:例如,某些对被冗余报告。但是,一般的想法应该是明确的:使用一个好的构建块来控制对的生成。