Prolog中的[[a,b] | c]列表

时间:2017-07-28 15:28:06

标签: prolog

在我探索不同的写下列表的方法时,我对下面的列表[[a,b]|c]很感兴趣,该列表出现在“Prolog and Natural Language Analysis' Pereira和Shieber(digital edition的第42页)。

起初我认为这样的符号在语法上是不正确的,因为它必须说[[a,b]|[c]],但在使用write_canonical/1后Prolog返回'.'('.'(a,'.'(b,[])),c)

据我所知,这对应于以下树结构(虽然对我来说似乎很奇怪,结构只会以c结尾,而最后没有空列表):

drawing of tree structure

我似乎无法使用逗号和括号找到相应的表示法。我认为它与[[a,b],c]相对应(但这显然会导致与write_canonical/1不同的结果)。

[[a,b]|c]是否没有相应的表示法,或者我是否以错误的方式看待它?

2 个答案:

答案 0 :(得分:4)

正如其他人已经指出的那样,术语[[a,b]|c] 不是一个列表。

您可以使用|语法自行测试,然后将其写下来:

?- is_list([[a,b]|c]).
false.

您可以从write_canonical/1看到此字词与您绘制的字词相同:

| ?- write_canonical([[a,b]|c]).
'.'('.'(a,'.'(b,[])),c)

除了其他人所说的内容之外,我还要发布一个额外的答案,因为我想解释一下如何找到意外失败的原因。从Prolog开始,您经常会问自己“为什么这个查询失败?”

查找此类问题的解释的一种方法是概括查询,使用逻辑变量而不是具体的术语。

例如,在上面的例子中,我们可以写:

?- is_list([[A,b]|c]).
false.

在这种情况下,我使用了逻辑变量 A 而不是原子a,从而大大推广了查询。由于通用查询仍然失败,因此剩余部分中的某些约束必须导致意外故障。我们进一步概括它以缩小原因。例如:

?- is_list([[A,B]|c]).
false.

甚至更进一步:

?- is_list([[A,B|_]|c]).
false.

更进一步:

?- is_list([_|c]).
false.

所以在这里我们拥有它:没有术语具有一般形式'.'(_, c)是一个列表!

正如您正确观察到的那样,这是因为这样的术语不是[_|Ls] Ls 列表的形式。

注意:我上面申请的声明性调试方法适用于Prolog的单调子集。实际上,is_list/1不属于该子集,因为我们有:

?- is_list(Ls).
false.

声明性读数“没有勺子列表。”因此,事实证明,在上述情况下,它只能巧合。但是,我们可以通过简单地应用列表的归纳定义,以纯粹和单调的方式定义is_list/1的预期声明含义:

list([]).
list([_|Ls]) :- list(Ls).

此定义仅使用纯粹和单调的构建块,因此是单调的。例如,最常见的查询现在产生实际列表而不是失败(错误地):

?- list(Ls).
Ls = [] ;
Ls = [_6656] ;
Ls = [_6656, _6662] ;
Ls = [_6656, _6662, _6668] .

从纯粹的关系中,我们希望查询在所有方向上运行!

答案 1 :(得分:2)

  

我似乎无法使用逗号和括号找到相应的符号。

没有相应的符号,因为从技术上讲这不是真正的清单。

Prolog为列表提供了合成糖。 Prolog中的列表与 Lisp 列表一样,实际上是一个链表:每个元素都是空列表[],或者是.(H,T) H的节点 head T tail 。列表不是特殊的"在Prolog中,解释器处理它们的方式与任何其他术语不同。当然,很多Prolog库都会列出处理,并使用上面定义的约定。

为了使复杂的列表更方便,发明了语法糖。您也可以像.(H,T)一样编写节点[H|T]。这意味着在[[a,b]|c]中。我们有一个外部列表,其中有一个节点.(H,c)?另一个列表,有两个节点和一个空列表H = .(a,.(b,[]))

从技术上讲,我不会认为这是真实的"列表,因为列表的尾部应该有另一个节点./2或空列表。

但是,您可以将此功能用于[[a,b]|C]之类的变量,以便进一步统一尾C。所以这里我们有一些列表,[a,b]作为第一个元素(所以包含列表的列表)和一个开放尾C。如果我们稍后将C转为C = [],则列表为[[a,b]]