理解差异列表(Prolog)

理解差异列表(Prolog),prolog,palindrome,difference-lists,Prolog,Palindrome,Difference Lists,我很难理解差异列表,尤其是在这个谓词中: palindrome(A, A). palindrome([_|A], A). palindrome([C|A], D) :- palindrome(A, B), B=[C|D]. 有人能帮我跟踪发生的事情吗 palindrome(A, A). palindrome([_|A], A). palindrome([C|A], D) :- palindrome(A, B), B=[C|D]. 将该谓词的参数视为差异列表,第一个子句

我很难理解差异列表,尤其是在这个谓词中:

palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
   palindrome(A, B),
   B=[C|D].
有人能帮我跟踪发生的事情吗

palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
   palindrome(A, B),
   B=[C|D].
将该谓词的参数视为差异列表,第一个子句说,从
a
a
的列表(即空列表)是回文

第二句说,一个元素列表是回文,不管这个元素是什么


不要惊慌!差异列表只是带有显式结尾“指针”的列表。

一个普通的列表,比如说
[1,2,3]
,是它的开始和结束之间的差异;正常列表的结尾总是空列表,
[]
。也就是说,对于一个列表
[1,2,3]
,我们应该将这个谓词称为
回文([1,2,3])
——也就是说,检查差异列表
[1,2,3]-[]
是否是回文

从操作的角度来看,差异列表只不过是一个(可能是开放式的)具有显式维护的“结束指针”的列表,例如:
a-Z
,其中
a=[1,2,3 | Z]
Z=[]
。实际上,
[1,2,3 |[]]
[1,2,3]
是一样的。但是当
Z
尚未实例化时,列表
A
仍然是开放式的-它的“结束指针”
Z
可以实例化为任何对象(当然,只有一次,没有回溯)

如果我们稍后将
Z
实例化为一个开放式列表,比如说,
Z=[4 | W]
,我们将得到一个新的扩展差异列表
a-W
,其中
a=[1,2,3,4 | W]
。旧的一个将成为
A-Z=[1,2,3,4 | W]-[4 | W]
,即仍然表示一个开放式列表的前缀
[1,2,3]
。一旦关闭,例如使用
W=[5]
,所有对数变量仍然表示其相应的差异列表(即
A-Z
A-W
…),但
A
不再是开放式的,因此不能再扩展

不使用
-
functor,通常只使用diff列表定义的两部分作为谓词的单独参数。当我们总是把它们当作一对中的两部分来使用/对待时,它们就在概念上形成了一对。是一样的


继续。第三句说,要使
[C|A]-D
成为回文,
A-B
必须是回文,
B
必须是
[C|D]
<代码>A、D、B是列表,
C
是列表的一个元素。这可能令人困惑;让我们改用
V
。此外,使用
Z
Y
代替
D
B
,提醒我们列表的“结尾”:

palindrome([V|A], Z):- palindrome(A, Y), Y=[V|Z].

V ................. V ----
  ^                 ^ ^
  |                 | |
  |                 | Z
  A                 Y = [V|Z]

事实上,当
核心是回文时,在其周围放置两个
V
s会给我们带来另一个回文。

下面是一个总结,希望能从前面的讨论中提炼出最好的内容,并添加一个小但重要的简化

首先,应该在当前问题的上下文中理解原始问题,可以将其表述为定义一个Prolog谓词,该谓词将检查列表是否是回文,或者更一般地说是生成回文。我们希望探索使用差异列表的实现,因此我们可以从以下方面开始:

% List is a palindrome if List - [] is a palindrome:
palindrome( List ) :- palindrome(List, []).  
(如其他地方所解释的,如果列表是两个列表的串联 前面和后面,然后前面可以被视为是不同的 在List和Back之间,也就是说,Front可以被视为等价于(List-Back)

为了定义回文/2,我们从两个“基本情况”开始,一个空列表和一个单例:

% The empty list (L-L) is a palindrome:
palindrome(L, L).

% A singleton list, ([X|L] - L), is a palindrome:
palindrome([X|L], L). 
现在让我们谈谈一般情况

如果一个包含多个元素的列表是回文,那么 将看起来像这样:E。。。E

在哪里。。。是一个(可能是空的)回文

加上一个尾巴,尾巴,我们的清单一定是这样的:E。。。尾翼

将这个常规列表写成[E|Rest],我们现在可以看到原始列表([E|Rest]-Tail)是回文,如果(Rest-[E|Tail])是回文, 或者根据我们的谓词回文/2:

很容易看出,这与原来的公式是等价的

就这样!例如,现在我们可以为回文生成模板:

?- palindrome( X ).
X = [] ;
X = [_G1247] ;
X = [_G1247, _G1247] ;
X = [_G1247, _G1253, _G1247] ;
X = [_G1247, _G1253, _G1253, _G1247] 
....

第一条似乎是错的,它的意思是identity@CapelliC:不是标识,而是空列表。@false我不懂。。。难道
A
不会与任何东西统一,而不仅仅是空列表吗?这怎么不是一种普遍的身份关系?@错,我想可能有一些沟通错误?我相信卡佩里克的话是在指出,正如这里所写的,第一条定义了身份。你是说,理想情况下,在回文正确实现的不同上下文中,这个子句应该是空列表吗?@aBathologist:OP的程序就是DCG的扩展。见我的第一条评论。因此,它必须用作回文(A,[])。您的“端点”指向哪里:
?-短语(n,[A],[b])。
带有
n,[b]-->[A]
?@false我们不应该这样称呼它。[a] -[b]不是一个差异列表。OP的
回文
是常规的Prolog谓词,而不是DCG规则,对吗?如果您不接受该示例,请相应地将其扩展到可以使用
短语/2
调用的内容。您的解释基于一个非常具体的属性,该属性不适用于每个DCG或差异列表;因此,这并不能解释它们的本质。而且:我不同意你所说的[a]-[b]不是一个不同的列表。在所有这些差异出现在DCG中之后,DCG使用差异列表。@false我不准备以任何程度的严格性来为我的类比辩护。这对我很有帮助。如果DCG规则接受[a]-[b],那么我可以认为它们比diff列表更大<代码>回文([a],[b])将失败,我认为这没有问题。我当然可能是
?- palindrome( X ).
X = [] ;
X = [_G1247] ;
X = [_G1247, _G1247] ;
X = [_G1247, _G1253, _G1247] ;
X = [_G1247, _G1253, _G1253, _G1247] 
....