如果我在 Prolog 中有一个列表,例如 X = [1, 2, 3, 4],如何将元素 5 添加到列表的末尾以使 X = [1, 2, 3, 4, 5]?
append 函数需要两个列表,即 append(A,B,C) 将 A 和 B 连接到列表 C。
我可以使用临时列表 Y = [1, 2, 3, 4] 和 Z = [5] 来执行此操作,然后执行附加(Y,Z,X),但我不喜欢临时列表。
通常的免责声明在这里适用——这不是家庭作业,我只是在学习 Prolog。
如果我在 Prolog 中有一个列表,例如 X = [1, 2, 3, 4],如何将元素 5 添加到列表的末尾以使 X = [1, 2, 3, 4, 5]?
append 函数需要两个列表,即 append(A,B,C) 将 A 和 B 连接到列表 C。
我可以使用临时列表 Y = [1, 2, 3, 4] 和 Z = [5] 来执行此操作,然后执行附加(Y,Z,X),但我不喜欢临时列表。
通常的免责声明在这里适用——这不是家庭作业,我只是在学习 Prolog。
正如其他人指出的那样,您将陷入性能问题。
但是作为一个练习,我决定尝试创建一个谓词,它可以将一个元素附加到列表的末尾,而不使用append
.
% add_tail(+List,+Element,-List)
% Add the given element to the end of the list, without using the "append" predicate.
add_tail([],X,[X]).
add_tail([H|T],X,[H|L]):-add_tail(T,X,L).
我建议您只需使用该append
功能,作为内置功能,它可能比任何手动制作的功能都要快。
Prolog 中的变量只能赋值一次。只要 X 具有值 [1,2,3,4],它就永远不会有另一个值。就像您提到的那样,临时变量和 append/3 是这样做的方法。
话虽如此,您可以做一个可能不推荐的技巧。如果 X = [1,2,3,4,Y] 那么你可以做 Y=5 并且 X 现在有你想要的值。我相信这种技术被称为差异列表。
一种声明性解决方案是使用差异列表(正如丹尼尔在其回答中建议的那样)。差异列表的名称通常表示为两个列表之间的差异:列表及其尾部。例如,一个空列表可以表示为T-T
。包含元素 1、2 和 3 的列表可以表示为[1,2,3| T]-T
(注意这(-)/2
是标准的内置中缀运算符)。这种表示的优点是您可以通过使用append/3
谓词的单个事实定义在恒定时间内将元素附加到列表中:
append(L1-T1, T1-T2, L1-T2).
一个使用示例:
?- append([1,2,3,4| T1]-T1, [5| T2]-T2, Result).
T1 = [5|T2],
Result = [1, 2, 3, 4, 5|T2]-T2.
如有必要,在“正常”列表和差异列表之间进行转换并不难。我把它作为练习留给你。
你不能在 Prolog 中修改列表,但是你可以创建一个未指定长度的列表:
main :-
A = [1,2,3,4|_].
nth0/3
然后,您可以在 SWI-Prolog 中使用插入元素:
:- initialization(main).
main :-
A = [1,2,3,4|_],
nth0(4,A,5),
writeln(A).
插入此元素后,A = [1,2,3,4,5|_]
.
您还可以定义一个将项目就地附加到列表末尾的函数,然后像这样使用它:
:- initialization(main).
append_to_list(List,Item) :-
List = [Start|[To_add|Rest]],
nonvar(Start),
(var(To_add),To_add=Item;append_to_list([To_add|Rest],Item)).
main :-
A = [1,2,3|_],
append_to_list(A,4),
append_to_list(A,4),
writeln(A).
在本例中,A = [1,2,3,4,4|_]
在这两个项目之后附加。
由于 Prolog 有 append 只接受列表,我们为什么不使用它来将我们的元素插入其中一个列表。IE
% E = element, L = list, R = result
% e.g. add_elem_in_list ([1,2,3,4], 5, R).
add_elem_in_list(L, E, R) :- append(L, [E], R).
你担心问题的错误结局。结构共享只能通过将一个元素放在列表的开头来实现。该方法具有您想要的性能特征。由于列表的定义方式,当您附加两个列表时,将复制整个第一个列表。在这种情况下,这将是整个列表。单项列表产生的垃圾显然会比这小得多。
如果您确实必须追加,请考虑向后构建列表,然后在末尾反转一次,这样会便宜得多,或者使用差异列表,这样可以有效地追加到末尾。