如果我在Prolog中有一个列表,例如X = [1,2,3,4],我如何将元素5添加到列表末尾以使X = [1,2,3,4, 5]
append函数需要两个列表,即追加(A,B,C)以获得A和B连接到列表C.
我可以用临时列表Y = [1,2,3,4]和Z = [5]来做这个,然后做一个追加(Y,Z,X),但我不喜欢有一个临时名单。
通常的免责声明适用于此 - 这不是家庭作业,我只是在学习Prolog。
答案 0 :(得分:7)
正如其他人所指出的那样,你将会遇到性能问题
但就像练习一样,我决定尝试创建一个谓词,可以将一个元素附加到列表的末尾,而不使用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
函数,作为内置函数,它可能比手动制作的任何函数都快。
答案 1 :(得分:6)
Prolog中的变量只能分配一次。只要X具有值[1,2,3,4],它就永远不会有另一个值。像你提到的那样,临时变量和附加/ 3就是这样做的方法。
话虽如此,你可以做一个可能不推荐的技巧。如果X = [1,2,3,4,Y]那么你可以做Y = 5而X现在有你想要的值。我相信这种技术被称为差异列表。
答案 2 :(得分:3)
一个声明性解决方案是使用差异列表(正如Daniel在其答案中所建议的那样)。差异列表的名称通常表示为两个列表之间的差异:列表及其尾部。例如,空列表可以表示为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.
如果有必要,在"正常"之间进行转换并不困难。列表和差异列表。我将此作为练习留给你。
答案 3 :(得分:2)
你担心问题的错误结束。结构共享只能通过将一个元素放到列表的开头来实现。该方法具有您想要的性能特征。由于定义了列表的方式,当您附加两个列表时,将复制整个第一个列表。在这种情况下,这将是整个列表。单项列表生成的垃圾显然要小得多。
如果你真的必须附加,请考虑向后构建列表,然后在结束时将其反转一次,这样便宜得多,或者使用差异列表,这样可以有效地追加到最后。
答案 4 :(得分:2)
您无法修改Prolog中的列表,但您可以创建一个未指定长度的列表:
main :-
A = [1,2,3,4|_].
然后,您可以在SWI-Prolog中使用nth0/3
插入元素:
:- 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|_]
。
答案 5 :(得分:1)
由于Prolog的附加只接受列表,为什么我们不使用它来将我们的元素插入其中一个列表中。即。
% 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).