2010-07-03 15 views
7

Di seguito è riportato il mio codice che prende un elemento dell'automobile di un elenco (carVal) e un elenco (inizializzato per lo svuotamento) come parametri. Voglio aggiungere l'elemento alla lista ma lo stesso non funziona.Aggiunta di un elemento all'Elenco nello schema

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

Il display mostra elenco vuoto tutto il tempo (). Qualcuno può aiutarmi a capire perché?

risposta

21

bene, c'è append! come un primitivo, che risolve la maggior parte dei vostri problemi, come detto già, Scheme tende ad aggrottare le sopracciglia su mutazione, è possibile, ma in genere evitato, quindi tutte le procedure che mutano hanno un ! (chiamato un botto) alla loro fine.

Inoltre, set! non mutare dei dati, cambia un ambiente, si fa un punto variabile per un'altra cosa, i dati originali rimane invariato.

La modifica dei dati in Schema è piuttosto macchinosa, ma per darti la mia implementazione di append! per vedere come è fatto:

(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)))) 

Nota l'uso di set-cdr!, che è un vero mutatore, funziona solo su coppie, esso muta i dati in memoria, a differenza di `set '!. Se una coppia viene passata a una funzione e mutata con set-cdr! o set-car !, è mutato ovunque nel programma.

Questo obbedisce all'app SRFI! specifica che dice che dovrebbe essere variadic e che dovrebbe restituire un valore indefinito, per esempio.

(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 

che visualizza:

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

Come visibile, aggiungere!può prendere un numero infinito di argomenti e li muta tutti tranne l'ultimo.

Schema potrebbe non essere la lingua ideale per te però. L'uso di append! come detto prima è non standard, invece, è preferibile append, che non muta e viene chiamato per il suo valore di ritorno. Che a implementare in quanto tale:

(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) 

che mostra uno stile Scheme più familiare in assenza di mutazione, pesante uso di ricorsione e nessun uso di sequenziamento.

Edit: Se si desidera solo aggiungere alcuni elementi a un elenco e non per se unire due però:

(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 

che fa quello che ci si aspetta

+0

Grazie per la risposta .. Btw .. 'nonna',' porn' .. Potresti volerli cambiare .. Altrimenti potresti essere giù votato :) –

+0

@ darkie15 Non rende la risposta meno 'utile' o ' chiaro ', se le persone vogliono svenderlo a causa di queste cose, allora questo sito è già perso. Inoltre, hai comunque la tua risposta. =) Inoltre, altre persone possono modificarlo se lo desiderano. – Zorf

2

(append foo bar)rendimenti la concatenazione di foo e bar. Non cambia né foobar.

0

È necessario aggiornare il valore di currVal con set !. Il vostro esempio dovrebbe avere

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

Si noti che questo cambierà 'currVal' all'interno della funzione, ma non avrà alcun effetto visibile all'esterno. –

5
  1. append crea un nuovo elenco , non modifica uno esistente.
  2. Questo perché, in generale, Scheme (e Racket in questo caso) è una lingua che preferisce lo stile funzionale.
  3. Si potrebbe ottenere un po 'più vicino con un set! - ma anche questo vi deluderà dal momento che modificherà solo l'associazione locale.
  4. Si noti che in Racket in particolare, gli elenchi sono immutabili, quindi non c'è niente che può modificare un elenco.
  5. Inoltre, anche se è possibile modificare un elenco in questo modo, è un modo molto inefficiente per accumulare lunghe liste, poiché è necessario scansionare ripetutamente l'intero elenco.
  6. Infine, se avete problemi a questo livello, allora vi consiglio vivamente di andare oltre HtDP
+0

Ho bisogno di venire con questa funzionalità. Cosa suggeriresti in questo caso? –

+0

Puoi usare un 'riquadro', che è un tipo di puntatore a un valore (mutabile). ** MA ** Dubito che tu abbia davvero bisogno di questa funzionalità - i neofiti spesso pensano di doverlo avere perché sono abituati a essere la mutazione l'unico modo di fare le cose. –

0

avete veramente bisogno di pensare a ciò che la funzionalità esatto si sta cercando

Se si desidera modificare una lista di riferimento, è necessario eseguire l'equivalente di append! (come notato nelle altre risposte). Ma questo è pericoloso, PERCHE 'potresti avere un altro codice che conta sulla lista essere immutabile, e se hai intenzione di farlo, la tua procedura deve avere un! alla fine per segnalare quel pericolo.

Un'approssimazione economico per quello che si vuole fare, in uno stile più funzionale, è:

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

Nota che fa una nuova lista, fa l'accodamento, visualizza il risultato, e restituisce il nuovo elenco come valore Questa è un'utile tecnica di debug se non si ha accesso al valore intermedio: esegui il bind su una variabile, visualizzalo o esegui il log, quindi restituiscilo.

Problemi correlati