为什么prolog会输出一个奇怪的树状列表?

为什么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

在这段序言代码中,我打算列出前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 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节点的输出就是如何打印的。原子,作为数字,不是列表