Prolog循环直到True
我对Prolog很陌生,但我正试图让这个程序给我第一组出现在N或N以上的孪生素数Prolog循环直到True,prolog,primes,Prolog,Primes,我对Prolog很陌生,但我正试图让这个程序给我第一组出现在N或N以上的孪生素数 twins(M) :- M2 is M + 2, twin_prime(M, M2), write(M), write(' '), write(M2). M3 is M + 1, twins(M3). 然而,我不完全确定如何让它循环并重复,直到它
twins(M) :-
M2 is M + 2,
twin_prime(M, M2),
write(M),
write(' '),
write(M2).
M3 is M + 1,
twins(M3).
然而,我不完全确定如何让它循环并重复,直到它成为真的。我曾尝试使用
repeat/0
谓词,但我只是陷入了一个无限循环。有没有人能给我一些建议?我对序言很陌生 有一个方便的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.
有一个方便的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.
使用尾部递归,您走上了正确的轨道,@Jake Mitchell的解决方案非常有效。但以下是一些技巧,可能有助于澄清Prolog中的一些基本概念: 首先,您的谓词
twins/1
实际上定义了两个数字之间的关系,即两个孪生素数。由于Prolog非常适合编写非常清晰、声明性的关系型程序,因此可以通过将谓词设置为twin_primes/2
,使谓词更加精确和明确。(这应该是一个二元谓词,这一点从您对谓词的命名中也非常清楚,因为一个事物不能是双胞胎…)
在描述二元关系时,显式使用二元谓词的一个很好的好处是,我们不再需要为了显示结果而对IO操作大惊小怪。我们只需查询twin_primes(X,Y)
,并将结果作为Prolog报告返回X
和Y
的可行值
第二,也是更重要的一点,您当前对双胞胎/1
的定义想要描述一种分离:“双胞胎(M)
如果M和M+2都是素数则为真,如果M3是M+3且双胞胎(M3)
为真,则为”。表达这种析取的基本方式是写多个分句。如果构成正文
的所有语句均为true,则格式为:-
的单个子句声明头
为true。几个标题相同的子句,如:-.:-.:-
,如果Body1
为真,则声明Head
为真;如果Body2
为真,则声明Head
为真。(请注意,定义谓词规则的一系列子句是自上而下顺序求值的。这一点非常重要,因为它将非声明性元素引入到我们的程序基础中,并且可以利用它来实现某些结果。)
事实上,您距离为twins/1
声明第二条规则只差一小步。您刚刚尝试将两个子句主体放在同一个head实例下。Prolog需要在这种情况下声明两个不同规则的冗余措施。您的代码应该很好(假设您对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的回溯功能,通常不需要通过尾部递归实现循环。例如,这里有一种替代方法,考虑到我之前的一些建议,并使用quick(但不是“高效”或“快速”)和dirty谓词生成素数:
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
从prime/1
获取一个质数,然后计算P2
并检查它是否为质数。由于prime/1
将在回溯时生成无穷多个素数,twin_primes/2
将一直向它询问数字,直到找到满意的解决方案。请注意,如果使用两个自由变量调用,则此双素数/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.
使用尾部递归,您走上了正确的轨道,@Jake Mitchell的解决方案非常有效。但以下是一些技巧,可能有助于澄清Prolog中的一些基本概念: 首先,您的谓词
twins/1
实际上定义了两个数字之间的关系,即两个孪生素数。由于Prolog非常适合编写非常清晰、声明性的关系型程序,因此可以通过将谓词设置为twin_primes/2
,使谓词更加精确和明确。(这应该是一个二元谓词,这一点从您对谓词的命名中也非常清楚,因为一个事物不能是双胞胎…)
在描述二元关系时,显式使用二元谓词的一个很好的好处是,我们不再需要为了显示结果而对IO操作大惊小怪。我们只需查询twin_primes(X,Y)
,并将结果作为Prolog报告返回X
和Y
的可行值
第二,也是更重要的一点,您当前对双胞胎/1
的定义想要描述一种分离:“双胞胎(M)
如果M和M+2都是素数则为真,如果M3是M+3且双胞胎(M3)
为真,则为”。表达这种析取的基本方式是写多个分句。如果构成正文
的所有语句均为true,则格式为:-
的单个子句声明头
为true。几个标题相同的子句,如:-.:-.:-
,如果Body1
为真,则声明Head
为真;如果Body2
为真,则声明Head
为真。(请注意,定义谓词规则的一系列子句是自上而下顺序求值的。这一点非常重要,因为它将非声明性元素引入到我们的程序基础中,并且可以利用它来实现某些结果。)
事实上,您距离为twins/1
声明第二条规则只差一小步。你刚才试着把两个子句主体都放在下面