2013-03-31 32 views
1

在这段序言代码,我打算列出前N素数,为什么prolog输出一个奇怪的树状列表?

(...) 

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]. 

我错过了什么?这让我很生气!

回答

1

好极了,所以你已经发现了将元素添加到列表的结尾的问题。在Prolog中,我们可以用

add(X,L,Z):- L=[X|Z]. 

等等,什么?如何阅读这个?我们必须知道这里的通话习惯。我们期待LZ进来作为未初始化变量,我们从现在开始安排L指向一个新创建的利弊节点与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是不是真的在这里需要的可以看到,因为它承载着[]下递归调用链,不变。因此,我们可以重新写primeListAcc没有Z参数,因此其最终条款将

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] 

[a|b]输出是一个缺点节点被刚刚的打印方式,当它的尾巴(在这里,b)是不是的一个列表。作为数字,原子是而不是列表。

+0

非常有用和彻底,谢谢! – rgcalsaverini

2

回想一下,列表要么是空列表[],要么是函子'.'和两个参数,其第二个参数是一个列表。语法[P|Ps]是术语'.'(P, Ps)的简写符号,如果Ps是一个列表(如您的示例中的情况),则这是一个列表。另一方面,术语'.'(Ps, P)(也可以写为[Ps|P](与您一样),是而不是列表如果P不是列表。您可以通过reverse/2获取反向列表。