2013-02-22 22 views
9

Jeśli mam listę w Prologu, taką jak X = [1, 2, 3, 4], w jaki sposób dodać element 5 na końcu listy, aby X = [1, 2, 3, 4, 5 ]?Prolog - jak dodać element do listy?

Funkcja dołączająca potrzebuje dwa wykazy, czyli dołączanie (A, B, C), aby A oraz B dołączona do listy C

może zrobić to z wykazu czasowego Y = [1, 2, 3, 4] i Z = [5], aby następnie dołączyć (Y, Z, X), ale nie lubię mieć listy tymczasowej.

Stosuje się tutaj zwykłe zrzeczenia się - to nie jest praca domowa i dopiero się uczę Prologu.

+1

Krótka odpowiedź: Nie; po prostu nie. – repeat

Odpowiedz

1

Zmienne w Prolog mogą być przypisane tylko raz. Jak tylko X ma wartość [1,2,3,4], nigdy nie może mieć innej wartości. Zmienna tymczasowa i dodatek/3, jak wspomniałeś, to sposób na zrobienie tego.

Powiedziawszy to, możesz zrobić jedną sztuczkę, która prawdopodobnie nie jest zalecana. Jeśli X = [1,2,3,4, Y], możesz zrobić Y = 5, a X ma teraz żądaną wartość. Wierzę, że ta technika nazywa się różnicą.

+0

@ Nikt w szczególności Nie traktuj zmiennych Prolog jako zmiennych matematycznych zamiast miejsc przechowywania. Zdaję sobie sprawę, że jest to duża zmiana paradygmatu, ale kiedy ją otrzymasz, wszystko w Prologu będzie całkiem łatwe (lub przynajmniej logiczne). –

+0

@mndrix - dobra odpowiedź. To czyści się wymyśla. Więc jeśli dobrze rozumiem, jeśli powiem X = [A, B, C, D], a następnie przypisz A = [1], B = [2], to X = [[1], [2], C, RE]. Później, jeśli przypiszę C = [3], D = [4], to w końcu mam X = [[1], [2], [3], [4]] i to jest naprawione w kamieniu. –

+0

@NoOneinParticular tak, to prawda – mndrix

1

Martwisz się złym końcem problemu. Współdzielenie struktury może się zdarzyć tylko przez umieszczenie elementu na początku listy. Ta metoda ma pożądaną charakterystykę wydajności. Ze względu na sposób definiowania list, po dołączeniu dwóch list zostanie skopiowana cała pierwsza lista. W tym przypadku będzie to cała lista. Śmieci generowane przez listę przedmiotów z jednego przedmiotu będą oczywiście znacznie mniejsze.

Jeśli naprawdę musisz dołączyć, rozważ utworzenie listy wstecz, a następnie cofnij ją raz na końcu, co jest znacznie tańsze, lub użyj list różnicowych, które umożliwiają efektywne dołączanie do końca.

+0

s (X) dla klasycznego podejścia "podwójna zmiana, pozycja z góry"! – repeat

4

Jak wskazali inni, utkniesz z problemem z wydajnością.
Jednak jako ćwiczenie postanowiłem spróbować stworzyć predykat, który może dopisać element na końcu listy, bez używania 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). 

radziłbym że chcesz po prostu użyć funkcji append jako wbudowaną funkcją jest prawdopodobnie szybciej niż cokolwiek ręcznie spreparowane.

+1

W stylu Benjamina Franklina: "* Ci, którzy zrezygnowaliby z istotnej poprawności, by zakupić tymczasową wydajność, nie zasługują ani na poprawność, ani na wydajność." " – repeat

+0

Jaka jest różnica między' add_tail (X, [L1], [L2]) 'i' add_tail (X, [Y | L1], [Z | L2]) '? – tamaramaria

+0

[Head1, Head2 | Tail] usunie pierwsze 2 zmienne z przodu listy, a resztę pozostawi na osobnej liście w zmiennej Ogon. Zatem [1,2,3,4] oznaczałoby Head1 = [1], Head2 = [2], Tail = [3,4], co oznacza, że ​​poprzez rekursję można usunąć przednie elementy listy. Add_tail wygląda następująco 1. Jeśli pierwsza lista jest pusta, a X jest teraz ostatnim elementem listy wyników, przestań szukać alternatyw. 2. Weź pierwszą zmienną z inputList, przekaż X dla sprawdzenia, rekursywnie unifikuj H do początku listy wyników, gdy 1. jest prawdziwe. 1. zapewnia powrót od tyłu. –

2

Jednym z deklaratywnych rozwiązań jest użycie listy różnic (jak sugerował Daniel w swojej odpowiedzi). Na liście różnicowej jej nazwa jest zwykle przedstawiana jako różnica między dwiema listami: listą i ogonem. Na przykład pusta lista może być reprezentowana jako T-T. Lista z elementami 1, 2 i 3 może być reprezentowana jako [1,2,3| T]-T (zauważ, że (-)/2 jest standardowym wbudowanym operatorem infiksów). Zaletą tej reprezentacji jest to, że można dodać element do listy w stałym czasie przy użyciu pojedynczego definicję fakt append/3 orzecznika:

append(L1-T1, T1-T2, L1-T2). 

Przykład użycia:

?- append([1,2,3,4| T1]-T1, [5| T2]-T2, Result). 
T1 = [5|T2], 
Result = [1, 2, 3, 4, 5|T2]-T2. 

Jeśli to konieczne, nie jest trudne do przekonwertowania między "normalną" listą a listą różnic. Zostawiam to jako ćwiczenie dla ciebie.

+1

Po prostu zauważyłem, że jest to bardzo stare pytanie (w czasie Internetu)! –

+0

s (X): lity jak skała. – repeat

0

Nie można modyfikować list w Prologu, ale można utworzyć listę o długości nieokreślonym:

main :- 
    A = [1,2,3,4|_]. 

Następnie można wstawić element używając nth0/3 w SWI-Prolog:

:- initialization(main). 

main :- 
    A = [1,2,3,4|_], 
    nth0(4,A,5), 
    writeln(A). 

Po wstawieniu tego elementu, A = [1,2,3,4,5|_].

Można również zdefiniować funkcję, która Dołącza element na końcu listy w miejscu, a następnie używać go tak:

:- 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). 

w tym przykładzie, A = [1,2,3,4,4|_] Po tych dwóch elementów są dołączone.

0

Od kiedy Prolog ma dodatek, który akceptuje tylko listy, dlaczego nie użyjemy wstawić nasz element na jednej z list. tj.

% 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).