2010-07-03 20 views
7

A continuación está mi código que toma un elemento de auto de una lista (carVal) y una lista (inicializada para vaciar) como parámetros. Quiero agregar el elemento a la lista, pero lo mismo no está funcionando.Agregando un elemento a la Lista en el Esquema

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

La pantalla muestra una lista vacía todo el tiempo (). ¿Alguien puede ayudarme a entender por qué?

Respuesta

21

Bueno, no es append! como primitiva, que resuelve la mayor parte de sus problemas, como ya se ha señalado, Esquema tiende a fruncir el ceño en la mutación, es posible, pero normalmente se evita, por lo que todos los procedimientos que mutan tienen un ! (llamado explosión) en su extremo.

Además, set! no muta de datos, cambia un entorno, tiene un punto variable a otra cosa, los datos originales se deja sin cambios.

Mutar los datos en Scheme es bastante engorroso, pero, para darle mi propia implementación de append! para ver cómo se hace:

(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 el uso de set-cdr!, que es un verdadero mutador, que sólo funciona en pares, que muta de datos en la memoria, a diferencia de `set '!. Si un par se pasa a una función y se muta con set-cdr! o set-car !, está mutado en todas partes en el programa.

¡Esto obedece a SRFI append! especificación que dice que debe ser variadic y que debe devolver un valor indefinido, por ejemplo.

(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 

que muestra:

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

Como es visible, anexar!puede tomar una cantidad infinita de argumentos y los muta todos menos al último.

Es posible que el esquema no sea el idioma ideal para usted. El uso de append! como se dijo antes no es estándar, en su lugar, se prefiere agregar, que no cambia y se solicita su valor de retorno. ¿Qué debo hacer para implementar tales como:

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

la cual muestra un estilo Esquema más familiar en la ausencia de la mutación, un uso intensivo de la recursividad y no uso de la secuenciación.

Editar: Si lo que desea es añadir algunos elementos a una lista y no es per se une a dos sin embargo:

(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 

que no es lo que esperas

+0

Gracias por la respuesta .. Btw .. 'abuelita',' porno' .. Es posible que desee cambiarlos .. De lo contrario, podría bajar votó :) –

+0

@ darkie15 No hace que la respuesta sea menos 'útil' o ' claro ', si la gente quiere rechazarlo debido a esas cosas, entonces este sitio ya está perdido. Además, tienes tu respuesta de todos modos. =) Además, otras personas pueden editarlo si lo desean. – Zorf

2

(append foo bar)vuelve la concatenación de foo y bar. Tampoco cambia foo o bar.

0

¡Tienes que actualizar el valor de currVal con set !. Su ejemplo debe tener

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

Tenga en cuenta que esto cambiará 'currVal' dentro de la función, pero no tendrá ningún efecto visible en el exterior. –

5
  1. append crea una nueva lista , no modifica una ya existente.
  2. Esto se debe a que, en general, Scheme (y Racket en este caso) es un lenguaje que prefiere el estilo funcional.
  3. Puede acercarse un poco más con set!, pero incluso eso lo decepcionará ya que modificará solo el enlace local.
  4. Tenga en cuenta que en Racket en particular, las listas son inmutables, por lo que hay nada que puede cambiar una lista.
  5. Además, incluso si pudiera modificar una lista de esta manera, es una manera muy ineficiente de acumular listas largas, ya que debe escanear toda la lista de manera repetida.
  6. Por último, si usted tiene problemas en este nivel, entonces te recomiendo ampliamente revisar HtDP
+0

Necesito encontrar esta funcionalidad. ¿Qué sugieres en este caso? –

+0

Puede usar una 'caja', que es una especie de puntero a un valor (mutable). ** PERO ** Dudo que realmente necesites esta funcionalidad: los novatos a menudo piensan que deben tener eso porque están acostumbrados a que la mutación sea la única forma de hacer las cosas. –

0

que realmente necesita para pensar en lo que la funcionalidad exacta usted está buscando

Si quiere mutar una lista referenciada en su lugar, ¡entonces tiene que hacer el equivalente de append! (como se señala en las otras respuestas). Pero eso es peligroso, PUES puede tener otro código que cuente con que la lista es inmutable, y si va a hacer eso, ¡su procedimiento debe tener un! al final para marcar ese peligro.

Una aproximación barata de lo que quiere hacer, en un estilo más funcional, es decir:

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

Tenga en cuenta que se hace una nueva lista, que hace el append, muestra el resultado, y devuelve la nueva lista como un valor Esta es una técnica de depuración útil si no tiene acceso al valor intermedio: enlazar a una variable, visualizarla o registrarla, y luego devolverla.

Cuestiones relacionadas