为什么prolog会输出一个奇怪的树状列表?
在这段序言代码中,我打算列出前N个素数为什么prolog会输出一个奇怪的树状列表?,prolog,primes,difference-lists,Prolog,Primes,Difference Lists,在这段序言代码中,我打算列出前N个素数 (...) biggerPrime(N,P) :- isPrime(N), P is N, !. biggerPrime(N,P) :- N1 = N+1, biggerPrime(N1,P). primeListAcc(0,A,R,R) :- !. primeList(N,L) :- primeListAcc(N,1,[],L). primeListAcc(N,A,L,R) :- N1 i
(...)
biggerPrime(N,P) :-
isPrime(N),
P is N,
!.
biggerPrime(N,P) :-
N1 = N+1,
biggerPrime(N1,P).
primeListAcc(0,A,R,R) :- !.
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[P|L],R).
如果我想让列表向后排序,它就可以正常工作:
?- primeList(5,L).
L = [11, 7, 5, 3, 2].
但如果我将代码的最后一行从[p | L]更改为[L | p],如下所示:
primeListAcc(N,A,L,R) :-
N1 is N-1,
biggerPrime(A,P),
A1 is P+1,
primeListAcc(N1,A1,[L|P],R).
我得到:
?- primeList(5,L).
L = [[[[[[]|2]|3]|5]|7]|11].
我错过了什么?这让我快发疯了 回想一下,列表要么是空列表
[]
,要么是一个带有functor'的术语。
和两个参数,其第二个参数是列表。语法[P | Ps]
是术语'(P,Ps)
的简写符号,如果Ps
是一个列表,那么它就是一个列表(如您的示例所示)。另一方面,术语。(Ps,P)
,也可以写成[Ps | P]
(正如您所做的那样),如果P
不是列表,则它不是列表。您可以使用reverse/2
获得反向列表,非常好,因此您发现了在列表末尾添加元素的问题。在Prolog中,我们可以使用
add(X,L,Z):- L=[X|Z].
等等,什么?怎么读这个?我们必须知道这里的通话惯例。我们希望L
和Z
作为未实例化的变量出现,我们从现在开始安排L
指向一个新创建的cons节点,其头部为X
,尾部为Z
Z
将在将来的某个调用中实例化
我们在这里创建的是一个开放式列表,L=[X | Z]=[X,…]
:
primeList(N,L) :-
primeListAcc(N,1,[],L).
primeListAcc(N,A,Z,L) :- N > 0, % make it explicitly mutually-exclusive,
N1 is N-1, % do not rely on red cuts which are easily
biggerPrime(A,P), % invalidated if clauses are re-arranged!
A1 is P+1,
L = [P|R], % make L be a new, open-ended node, holding P
primeListAcc(N1,A1,Z,R). % R, the tail of L, to be instantiated further
primeListAcc(0,A,R,R). % keep the predicate's clauses together
现在我们可以看到,这里并不真正需要Z
,因为它在递归调用链中携带[]
,没有改变。因此,我们可以在不使用Z
参数的情况下重新编写primeListAcc
,这样它的最终子句将是
primeListAcc(0,A,R):- R=[].
将Z
作为未实例化的变量保留,这样以后就可以使用非空列表对其进行实例化(当然,只有一次(除非发生回溯))。这构成了“差异列表”技术的基础
回答你的字面问题-在这里,考虑这个互动记录:
1 ?- X=[a|b].
X = [a|b]
2 ?- X=[a|b], Y=[X|c].
X = [a|b]
Y = [[a|b]|c]
当cons节点的尾部(此处为b
)不是列表时,cons节点的输出就是如何打印的。原子,作为数字,不是列表