通过 Prolog 中的列表递归

Recursion through a list in Prolog

我正在尝试在 Prolog 中反转列表。当我用 ['item1', 'item2'] 调用它时它工作正常,但当我用 ['item1'|'item2'] 调用它时却不行。我是 Prolog 的初学者,但我认为这两种表示法本质上可以互换?

这是我使用的代码:

reverse_list([], Acc, Acc).
reverse_list([Head|Tail], Acc, Reversed) :-
    reverse_list(Tail, [Head|Acc], Reversed). 

reverse_list(List,Reversed) :-
    reverse_list(List,[],Reversed).

问题出在用列表的尾部进行递归调用时

当我用列表 ['item1', 'item2'] 调用它时,调试器显示它工作正常,使用尾部作为 ['item2'] 进行递归调用,这是应该的。

当我用 ['item1'|'item2'] 调用它时,调试器显示它试图用 'item2' 进行递归调用,但失败了,大概是因为它不是列表。

我读到使用 [Head|Tail] 时 Tail 将始终是一个列表,但看起来这里不是这种情况。

您能否解释一下 Prolog 如何处理这些列表,以及为什么这两种表示列表的方式不能互换?你能解释一下如何使这段代码起作用吗?

谢谢!

列表的尾部是一个列表。例如:

| ?- [1,2,3] = [Head| Tail].
Head = 1
Tail = [2,3]
yes

您用作参数的复合词 ['item1'|'item2'] 不是 列表:

| ?- ['item1'|'item2'] = [Head| Tail].
Head = item1
Tail = item2
yes

您需要改为 [item1|[item2]],这与 [item1,item2]:

完全相同
| ?- [item1|[item2]] = [item1,item2]. 
yes

由于列表表示法是语法糖,您可以使用标准 write_canonical/1 谓词来检查列表结构:

| ?- write_canonical([1,2,3]).       
'.'(1,'.'(2,'.'(3,[])))
yes

| ?- write_canonical([item1, item2]).
'.'(item1,'.'(item2,[]))
yes

| ?- write_canonical([item1| item2]).
'.'(item1,item2)
yes

当调用 reverse_list([item1|[item2]], Reversed) 时,目标在第一次递归调用时失败,因为您得到 reverse_list(item2, ..., ...),它不与 reverse_list/3 的子句的任何头部统一谓词,因此无法证明。因此,您的谓词定义没有任何问题。只是对列表表示的误解。