在我探索不同的写下列表的方法时,我对下面的列表[[a,b]|c]
很感兴趣,该列表出现在“Prolog and Natural Language Analysis' Pereira和Shieber(digital edition的第42页)。
起初我认为这样的符号在语法上是不正确的,因为它必须说[[a,b]|[c]]
,但在使用write_canonical/1
后Prolog返回'.'('.'(a,'.'(b,[])),c)
。
据我所知,这对应于以下树结构(虽然对我来说似乎很奇怪,结构只会以c
结尾,而最后没有空列表):
我似乎无法使用逗号和括号找到相应的表示法。我认为它与[[a,b],c]
相对应(但这显然会导致与write_canonical/1
不同的结果)。
[[a,b]|c]
是否没有相应的表示法,或者我是否以错误的方式看待它?
答案 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]]
。