【问题标题】:Understanding difference lists (Prolog)了解差异列表 (Prolog)
【发布时间】:2013-12-08 19:25:04
【问题描述】:

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

palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
   palindrome(A, B),
   B=[C|D].

谁能帮我看看发生了什么?

【问题讨论】:

  • 第一个子句好像错了,代表身份
  • @CapelliC:不是身份,而是空列表。
  • @false 我不关注... A 不会与任何东西统一,而不仅仅是空列表?这怎么不是一般的身份关系?
  • @false 我认为可能存在一些误传?我相信 CapelliC 的评论是指出 as write here 第一个子句定义了身份。您是说理想情况下,在正确实现回文的不同上下文中,此子句应该是空列表吗?
  • @aBathologist:OP 的程序是 DCG 的扩展。请参阅我的第一条评论。因此,它必须用作palindrom(A,[]).

标签: prolog palindrome difference-lists


【解决方案1】:
palindrome(A, A).
palindrome([_|A], A).
palindrome([C|A], D) :-
   palindrome(A, B),
   B=[C|D].

将此谓词的参数视为差异列表,第一个子句说,从AA 的列表(即空列表)是回文。

第二个子句说,一个单元素列表是一个回文,不管那个元素是什么。


不要惊慌! 差异列表只是带有明确结束“指针”的列表

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

从操作的角度来看,差异列表只不过是一个(可能是开放式的)列表,其中明确维护了“结束指针”,例如:A - Z where A = [1,2,3|Z] and 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,4 ...] 的前缀[1,2,3]。一旦关闭,例如使用W = [5],所有的logvars对仍然代表它们对应的差异列表(即A - ZA - W ...),但A不再是开放式的,所以不能再扩展了。

不使用- 函子,习惯上只使用差异列表定义的两个部分作为谓词的单独参数。当我们总是把它们当作一对的两个部分来使用/对待时,它们在概念上就形成了一对。都是一样的。


继续。第三个子句说,[C|A]-D 是回文,A-B 必须是回文,B 必须是 [C|D]A, D, B 是列表,C 是列表的元素。这可能会令人困惑;让我们改用V。此外,使用ZY 代替DB,提醒我们列表的“结尾”:

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

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

确实,当...... 核心是回文时,在其周围放置两个Vs 会给我们另一个回文。

【讨论】:

  • 你的“端点”指向哪里:?- phrase(n,[a],[b]).n, [b] --> [a]
  • @false 我们不应该这样称呼它。 [a]-[b] 不是差异列表。 OP 的 palindrome 是常规 Prolog 谓词,而不是 DCG 规则,对吗?
  • 如果您不接受该示例,请将其扩展为可以使用phrase/2 调用的内容。您的解释基于一个非常具体的属性,该属性不适用于每个 DCG 或差异列表;因此不能解释它们的本质。并且:我不同意您关于 [a]-[b] 不是差异列表的说法。毕竟这些差异都发生在 DCG 中,而 DCG 使用差异列表。
  • @false 我不准备为我的类比进行任何严格程度的辩护。这对我很有帮助。如果 DCG 规则接受 [a]-[b],那么我可以将它们视为比差异列表更大。 palindrome([a],[b]) 将失败,我认为这没有问题。当然,我可能是错的,并且会很高兴被告知在哪里以及为什么。
  • AoP 让我很困惑。由于我之前使用过编码,但不确定这是否是 Wisdom-Prolog 特有的(至少在第一版中被宣传)。
【解决方案2】:

以下是一个摘要,希望能提炼出前面讨论的精华,并添加一个小而重要的简化。

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

% List is a palindrome if List - [] is a palindrome:
palindrome( List ) :- palindrome(List, []).  

(正如在别处解释的那样,如果一个列表 List 是两个列表的串联 Front 和 Back,然后 Front 可以看作是区别 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

其中 ... 是一个(可能是空的)回文。

添加尾巴,Tail,我们的列表必须看起来像:E ... E Tail

将此常规列表写为 [E|Rest],我们现在可以看到,如果 (Rest - [E|Tail]) 是回文,则原始列表 ( [E|Rest] - Tail ) 是回文, 或者就我们的谓词palindrome/2而言:

palindrome( [E|Xs], Tail ) :- palindrome(Xs, [E|Tail]).

很容易看出这和原来的公式是等价的。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多