Prolog中追加列表和原子的方法

3

我对Prolog还比较陌生,我尝试了以下代码:

| ?- append([1],2,R).

R = [1|2]

yes

我不知道符号[1 | 2]的含义。我试图搜索相关信息,但非常艰难,没有找到任何内容。我猜这类似于Lisp中由(cons 1 2)生成的(1 . 2)。能否有人解释或提供相关说明?
如果有用的话,我正在使用GNU-prolog版本1.3.0。
1个回答

3
“General”形式的[H|T] 列表符号[H|T]是通过头和尾定义列表的谓词'.'(H,T)的语法糖。例如,列表[1,2,3]也可以写成'.'(1,'.'(2,'.'(3,[])))。(在Prolog提示符下尝试执行X = '.'(1,'.'(2,'.'(3,[]))).
由于您似乎熟悉Lisp,因此用那些术语来说,X是列表[X|T]carT是列表[X|T]cdrappend/3通常与列表参数一起使用,所以要将一个称为atom的原子附加到列表L并使结果为R,可以这样做:
append(L, [atom], R).

更具体地说:
append([1], [2], R).

产出:R = [1,2]

在使用append/3rev/2定义实现时,Clocksin&Mellish的《Prolog编程》,第五版,在p.157中指出:

按照惯例,列表的尾部始终是一个列表。

如果给定一个列表L,可以通过与[H|T]形式相一致来检索头(car)和尾(cdr):

L = [H|T]

例如:

| ?- L = [1,2,3,4], L = [H|T].

H = 1
L = [1,2,3,4]
T = [2,3,4]

yes
| ?-

您可以随意拆卸所需的任何元素:
| ?- L = [1,2,3,4], L = [A,B,C|T].

A = 1
B = 2
C = 3
L = [1,2,3,4]
T = [4]

yes

如果您尝试执行过多的操作,它将失败:

| ?- L = [1,2,3], L = [A,B,C,D|T].

no

[H|T]形式在列表处理谓词中非常方便,特别是递归的情况下。

my_list_process_predicate([H|T], [Result|Results]) :-
    % Do some stuff here, determing "Result" from "H" perhaps
    my_list_processing_predicate(T, Results).  % Get the rest of the results
                                               % from the rest of the list

如果你要按照 [H|T] 的形式字面上写出列表 [1,2,3],那么有以下等价表达方式:
[1,2,3|[]]
[1,2|[3]]
[1,2|[3|[]]]
[1|[2,3]]
[1|[2,3|[]]]
[1|[2|[3]]]
[1|[2|[3|[]]]]

T是原子时,列表形式为[H|T]

如果有一个列表[X|T],表示X是列表的头部,T是尾部(通常也是一个列表)。虽然 Prolog 可以构造这样的列表,其中 T 是原子,但它似乎不常用,至少不像 Lisp 中那样。但是,是的,[1|2] 确实像 Lisp 中的 (1 . 2)。Lisp 有一些内置函数,可以操作 (a . b) 形式的键值对等列表。Prolog 没有利用我所知道的 [a|b] 结构的任何内置函数。他们可能没有更多的优势,只是使用 [a,b]。我还搜索了有关 [a|b](或 [a1,...,an|b])形式的参考文献,并在 Clocksin&Mellish 的第53页找到了一个例子,将 [white|Q][P|horse] 统一:

…可以使用列表符号创建类似于列表但并不以空列表结尾的结构。其中一个这样的结构,[white|horse],表示具有头部 white 和尾部 horse 的结构。常量 horse 既不是列表也不是空列表,…在将这样的结构用于列表的尾部时应谨慎处理。

有趣的是,大多数其他处理列表的内置 Prolog 谓词实际上会在给定 [a1,...,an|b] 形式时失败。例如,在 GNU Prolog 中:

| ?- X = [1,2,3|4], length(X, L).

no
| ?- X = [1,2,3,4], length(X, L).

L = 4
X = [1,2,3,4]

yes

SWI Prolog 抛出异常:

?- X = [1,2,3|4], length(X, L).
ERROR: length/2: Type error: `list' expected, found `4'

类似的结果也会出现在其他谓词中。 maplist 可以处理这样一个列表的所有元素,但会忽略尾部原子。只要第一个列表没有原子作为其尾部,append/3 就可以工作。
关于列表中的原子作为尾部的问题是一个非常好的问题。它似乎被允许(例如,你可以统一 X=[1|2]),而内置的 append/3 处理它(可能是由于其简单的设计)。它可以用作有效的数据形式,[a1,...,an|b],并且可以与类似的形式统一。但大多数内置程序似乎没有正确地处理它。它也不作为通用的二元函数(尝试统一 X=3|4 会失败)。
因此,形式 [a1,...,an|b](其中 b 是一个原子)是一个有效的 Prolog 数据结构,但它作为列表的行为必须小心处理,因为大多数谓词假定列表的尾部是一个列表,并且“最终”尾部是空列表 []。因此,如果需要,它可以被合法地使用,但要小心(如 C&M 所指出的)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接