Как добавить элемент в список на месте в 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), но мне не нравится иметь временный список.
обычные оговорки применяются здесь - это не домашнее задание и я я просто изучаю Пролог.
6 ответов
переменные в прологе могут быть назначены только один раз. Как только X имеет значение [1,2,3,4], оно никогда не может иметь другого значения. Временная переменная и добавление/3, Как вы упомянули, - это способ сделать это.
сказав это, вы можете сделать один трюк, который, вероятно, не рекомендуется. Если X = [1,2,3,4, Y], то вы можете сделать Y=5 и X теперь имеет значение, которое вы хотите. Я считаю, что этот метод называется списком различий.
как указывали другие, вы будете застрять с проблемой производительности.
Но как упражнение я решил попробовать создать предикат, который мог бы добавить элемент в конец списка, не используя 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
функция, как встроенная функция, скорее всего, будет быстрее, чем что-либо созданное вручную.
одним декларативным решением является использование списка различий (как предложил Даниэль в своем ответе). Список различий получает свое имя от того, что обычно представляется как разница между двумя списками: списком и его хвостом. Например, пустой список можно представить как T-T
. Список с элементами 1, 2 и 3 может быть представлен как [1,2,3| T]-T
(заметим, что (-)/2
стандартный встроенный оператор infix). Преимущество такого представления заключается в том, что вы можете добавить элемент в список в постоянном время, используя одно определение факта 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 имеет приложение, которое принимает только списки, почему бы нам не использовать его для вставки нашего элемента в один из списков. т. е.
% 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).