Prolog循环直到True

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). 然而,我不完全确定如何让它循环并重复,直到它

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

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
声明第二条规则只差一小步。你刚才试着把两个子句主体都放在下面