我对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的新手。
答案 0 :(得分:3)
使用尾递归你是在正确的轨道上,@ Jake Mitchell的解决方案可以实现膨胀。但是这里有一些技巧可能有助于澄清Prolog中的一些基本概念:
首先,似乎你的谓词twins/1
实际上定义了 2 数字之间的关系,即两个孪生素数。由于Prolog非常适合编写非常清晰的声明性关系程序,因此可以通过将谓词设为twin_primes/2
来使谓词更加精确和明确。 (这应该是一个二元谓词,从你的谓词名称中也很清楚,因为有一件事不能是双胞胎...)
在描述二元关系时明确使用二元谓词的一个好处是我们不再需要对IO操作大惊小怪来显示结果。我们只需查询twin_primes(X,Y)
,并在Prolog报告X
和Y
的可行值时返回结果。
其次,更重要的是,您当前对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
P2
从prime/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.