2010-07-03 7 views
7

Poniżej znajduje się mój kod, który pobiera element samochodu z listy (carVal) oraz listę (zainicjowaną jako pusta) jako parametry. Chcę dodać element do listy, ale to samo nie działa.Dodawanie elementu do listy w schemacie

(define populateValues 
    (lambda (carVal currVal) 
     (append currVal(list carVal)) 
     (display currVal))) 

Wyświetlacz pokazuje pustą listę cały czas (). Czy ktoś może mi pomóc zrozumieć dlaczego?

Odpowiedz

21

Cóż, jest append! jako prymitywne, która rozwiązuje większość problemów, jak zauważył już, Schemat wydaje się krzywić w przypadku mutacji jest to możliwe, ale zazwyczaj unikane, więc wszystkie procedury, które mutują, mają na końcu koniec ! (zwany hukiem).

Ponadto, set! nie zmienia danych, zmienia środowisko , zmienia punkt na inną rzecz, oryginalne dane pozostają niezmienione.

Mutowanie danych w Schemacie jest dość kłopotliwe, ale w celu uzyskania własnej implementacji dołączenia! aby zobaczyć, jak to się robi:

(define (append! lst . lsts) 
    (if (not (null? lsts)) 
     (if (null? (cdr lst)) 
      (begin 
      (set-cdr! lst (car lsts)) 
      (apply append! (car lsts) (cdr lsts))) 

      (apply append! (cdr lst) lsts)))) 

Uwaga wykorzystanie set-cdr!, który jest prawdziwym mutator, to działa tylko w parach, to mutuje dane w pamięci, w przeciwieństwie do `set„!. Jeśli para zostanie przekazana do funkcji i zmutowana za pomocą set-cdr! lub set-car !, jest zmutowany w każdym miejscu programu.

Jest to zgodne z załącznikiem SRFI! spec, która mówi, że powinna być zmienna i że powinna zwracać na przykład niezdefiniowaną wartość.

(define l1 (list 1 2 3 4)) 

(define l2 (list 2 3 4)) 

(define l3 (list 3 1)) 

(append! l1 l2 l3) 

l1 

l2 

l3 

który wyświetla:

(1 2 3 4 2 3 4 3 1) 
(2 3 4 3 1) 
(3 1) 

Jak widać, dołącz!może wziąć nieskończoną liczbę argumentów i mutuje je wszystkie oprócz ostatniego.

Schemat może nie być idealnym językiem dla Ciebie. Korzystanie z append! jak wspomniano wcześniej, jest niestandardowy, zamiast tego preferowany jest append, który nie mutuje i jest nazywany wartością zwracaną. Które zaimplementować jako takie:

(define (append . lsts) 
    (cond 
    ((null? lsts) '()) 
    ((null? (car lsts)) (apply append (cdr lsts))) 
    (else (cons (caar lsts) (apply append (cdar lsts) (cdr lsts)))))) 


> (append (list 1 2 3) (list 4 5 6) (list 'granny 'porn)) 
(1 2 3 4 5 6 granny porn) 

który pokazuje bardziej znajomy styl programu w przypadku braku mutacji, intensywnego użytkowania rekursji i bez użycia sekwencjonowania.

Edycja: Jeśli chcesz po prostu dodać kilka elementów do listy, a nie per se dołączyć dwa choć:

(define (extend l . xs) 
    (if (null? l) 
     xs 
     (cons (car l) (apply extend (cdr l) xs)))) 

(define (extend! l . xs) 
    (if (null? (cdr l)) 
     (set-cdr! l xs) 
     (apply extend! (cdr l) xs))) 

(extend '(0 1 2 3) 4 5 6) 

(define list1 '(0 1 2 3)) 

(extend! list1 4 5 6) 

list1 

która robi to, czego oczekują

+0

Dzięki za odpowiedź .. Btw .. 'babcia',' porno' .. Możesz chcieć je zmienić .. Inaczej możesz dostać głosowanie :) –

+0

@ darkie15 To nie czyni odpowiedzi mniej "użyteczną" lub " jasne ", jeśli ludzie chcą to zrobić z powodu tych rzeczy, to ta strona jest już zagubiona. Zresztą i tak masz odpowiedź. =) Poza tym inne osoby mogą je edytować, jeśli zechcą. – Zorf

2

(append foo bar)powraca konkatenację foo i bar. Nie zmienia się ani foo ani bar.

0

Należy zaktualizować wartość currVal za pomocą set !. Twój przykład powinien mieć

(set! currVal (append currVal (list carVal)) 
(display currVal) 
+0

Zauważ, że to zmieni 'currVal' wewnątrz funkcji, ale nie będzie miało widocznego efektu na zewnątrz. –

5
  1. append tworzy nową listę, to nie zmienia istniejącego.
  2. Dzieje się tak, ponieważ ogólnie rzecz biorąc, Schemat (i Racket w tym przypadku) jest językiem, który preferuje styl funkcjonalny.
  3. Możesz zbliżyć się nieco dzięki set! - ale nawet to cię rozczaruje, ponieważ zmodyfikuje tylko lokalne powiązanie.
  4. Należy zauważyć, że w szczególności w rakietach listy są niezmienne, więc istnieje nic, co może zmienić listę.
  5. Co więcej, nawet jeśli można zmodyfikować listę w ten sposób, jest to bardzo nieefektywny sposób gromadzenia długich list, ponieważ trzeba wielokrotnie skanować całą listę.
  6. Wreszcie, jeśli masz problemy na tym poziomie, to zdecydowanie polecam jechać nad HtDP
+0

Muszę wymyślić tę funkcjonalność. Co zasugerowałbyś w tym przypadku? –

+0

Możesz użyć 'box', który jest rodzajem wskaźnika do wartości (zmiennej). ** ALE ** Wątpię, czy naprawdę potrzebujesz tej funkcjonalności - początkujący często myślą, że muszą to mieć, ponieważ są przyzwyczajeni do mutacji jako jedynego sposobu na robienie rzeczy. –

0

Naprawdę trzeba myśleć o tym, co dokładnie funkcjonalności szukasz

Jeśli chcesz zmutować listę odniesienia w miejscu, musisz zrobić ekwiwalent dołączyć! (jak zauważono w innych odpowiedziach). Ale to jest niebezpieczne, PONIEWAŻ możesz mieć inny kod, który liczy na niezmienność listy, a jeśli masz zamiar to zrobić, twoja procedura musi mieć! na koniec, aby oznaczyć to niebezpieczeństwo.

Tani przybliżeniem tego, co chcesz zrobić, w stylu bardziej funkcjonalnej jest:

(define (populateValues carVal currVal) 
(let ((ll (append currVal (list carVal)))) 
    (display ll) 
    ll)) 

Zauważ, że to sprawia, że ​​nową listę, robi dodać, wyświetla wynik i zwraca nową listę jako wartość. Jest to przydatna technika debugowania, jeśli nie masz dostępu do wartości pośredniej: połącz ją ze zmienną, wyświetl lub zapisz ją, a następnie zwróć.