如何在Prolog中生成所有自然数?

时间:2018-01-01 21:47:11

标签: prolog

问题陈述:

我正在尝试在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...

1 个答案:

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

这显然不完美:例如,某些对被冗余报告。但是,一般的想法应该是明确的:使用一个好的构建块来控制对的生成。