Prolog循环直到True

时间:2014-05-02 06:23:08

标签: prolog primes

我对Prolog很新,但我正试图让这个程序给我第一组出现在N或以上的孪生素数。

twins(M) :- 
            M2 is M + 2,
            twin_prime(M, M2),
            write(M),
            write(' '),
            write(M2).
            M3 is M + 1,
            twins(M3).

然而,我并不完全确定如何让它循环并重复直到它是真的。我尝试过使用repeat/0谓词,但我陷入无限循环。有没有人有我可以尝试的提示?我是Prolog的新手。

2 个答案:

答案 0 :(得分:3)

使用尾递归你是在正确的轨道上,@ Jake Mitchell的解决方案可以实现膨胀。但是这里有一些技巧可能有助于澄清Prolog中的一些基本概念:

首先,似乎你的谓词twins/1实际上定义了 2 数字之间的关系,即两个孪生素数。由于Prolog非常适合编写非常清晰的声明性关系程序,因此可以通过将谓词设为twin_primes/2来使谓词更加精确和明确。 (这应该是一个二元谓词,从你的谓词名称中也很清楚,因为有一件事不能是双胞胎...)

在描述二元关系时明确使用二元谓词的一个好处是我们不再需要对IO操作大惊小怪来显示结果。我们只需查询twin_primes(X,Y),并在Prolog报告XY的可行值时返回结果。

其次,更重要的是,您当前对twins/1的定义想要描述析取:如果M和M + 2都是素数twins(M)为真>或如果M3为M + 3且twins(M3)为真“。表达这种分离的基本方法是编写多个子句<Head> :- <Body>形式的单个子句声明如果构成Head的所有语句都为真,则Body为真。如果<Head> :- <Body1>. <Head> :- <Body2>. ...为真,那么Head如果Body1为真,则表示Body2为真;如果twins/1为真,则表示twin_prime/2为真。 (请注意,定义谓词规则的一系列子句从上到下依次进行评估。这非常重要,因为它将非声明性元素引入到程序的基础中,并且可以利用它来实现某些结果。 )

事实上,您只需要为twins(M) :- M2 is M + 2, twin_prime(M, M2), write(M), write(' '), write(M2). twins(M) :- \+twin_prime(M, M2), %% `\+` means "not" M3 is M + 1, twins(M3). 声明第二条规则,只需要一小步。您刚刚尝试将两个子主体放在同一个头实例下。 Prolog需要在这种情况下声明两个不同规则的冗余措施。您的代码应该没问题(假设您的prime(2). prime(P) :- between(2,inf,P), N is (P // 2 + 1), forall(between(2,N,Divisor), \+(0 is P mod Divisor)). twin_primes(P1, P2) :- prime(P1), P2 is P1 + 2, prime(P2). 定义有效),如果您只是改变它:

twin_primes/2

请注意,如果您利用Prolog的反向跟踪,通常不需要通过尾递归来实现循环。例如,这是另一种方法,考虑到我之前建议的一些内容,并使用快速(但不是“高效”或“快速”)和脏谓词来生成素数:

prime/1

P2prime/1获取素数,然后计算twin_primes/2并检查它是否为素数。由于twin_primes/2会在回溯时产生无限数量的素数,?- twin_primes(P1, P2). P1 = 3, P2 = 5 ; P1 = 5, P2 = 7 ; P1 = 11, P2 = 13 ; P1 = 17, P2 = 19 ; P1 = 29, P2 = 31 ; 只会在找到满意的解决方案之前不断询问数字。请注意,如果使用两个自由变量调用,则此P1将生成双素数:

P2

但它也会验证两个数字是否是孪生素数,如果查询具体值,或者给你一个素数的孪生,如果它存在,如果你给?- twin_primes(3,Y). Y = 5. 的值,但是留下{{1} } free:

{{1}}

答案 1 :(得分:1)

有一个方便的if-then-else运算符,适用于此。

twin_prime(3,5).
twin_prime(5,7).
twin_prime(11,13).

next_twin(N) :-
    A is N+1,
    B is N+2,
    (twin_prime(N,B) ->
     write(N),
     write(' '),
     write(B)
    ;
     next_twin(A)).

快速测试:

?- next_twin(5).
5 7
true.

?- next_twin(6).
11 13
true.