Macros de esquema: ¿emparejar en la transformación pero listar como salida?

Digamos que tengo la siguiente macro en R5Esquema RS:

(define-syntax pair-test
  (syntax-rules ()
     ((_ (a b . c))
      (quote (a b . c)))))

La macro transforma un par de entrada en un par de salida, como cabría esperar:

(pair-test (1 2 . 3))
==> (1 2 . 3)

También puedo pasar una lista a la macro, según lo permita la especificación. Sin embargo, la salida es una lista en lugar de un par:

(pair-test (1 2 3))
==> (1 2 3)

Qué está pasando aquí? ¿Por qué la salida es una lista en lugar de un par?

preguntado el 28 de agosto de 11 a las 00:08

2 Respuestas

Podría c be (3 . ()) en el segundo caso? No soy positivo, pero eso tendría sentido para mí. Y luego citando (a b . c) sería (1 2 . (3 . ())) cual es (1 2 . (3)) y (3) es una lista adecuada, así que (1 2 3)?

Respondido 28 ago 11, 06:08

Si. En realidad, c es (3 . ())--- las comillas adicionales que tienes no deberían estar ahí --- pero esencialmente tienes razón. - Ryan Culpepper

Para ver lo que está sucediendo aquí, necesita saber que una lista en Scheme es una cadena recursiva de pares de elementos y otras listas. Cualquier dato que siga la forma de una lista siempre se imprimirá como una lista. Una vez que sepa cómo se construyen las listas básicas, podrá ver lo que está sucediendo dentro de su macro.

Los pares en el esquema se pueden crear usando el . operador, o usando el cons función. Aquí hay un simple par de números:

(quote (1 . 2))
==> '(1 . 2)
(cons 1 2)
==> '(1 . 2)

Para crear una lista de 1 en Scheme, puede hacer un par con algo y la lista vacía:

(quote (1 . ()))
==> '(1)
(cons 1 (list))
==> '(1)

Una lista de 2 es un par de algo de algo en el lado izquierdo y una lista de 1 en el lado derecho. Asimismo, una lista de 3 es un elemento emparejado con una lista de 2:

(quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons 1 (cons 2 (cons 3 (list))))
==> '(1 2 3)

Para ver lo que está haciendo su macro, puede reorganizar el (quote (a b . c)) para ser más explícito:

(quote (a . (b . c)))
(cons (quote a) (cons (quote b) (quote c)))

Ahora puede ver que este formulario se parece mucho a cuando está construyendo una lista. Si (quote c) da como resultado una lista, entonces toda la expresión será una lista. En el caso de (pair-test (1 2 3)), c se convierte en (3 . ()):

(quote (a . (b . c)))
==> (quote (1 . (2 . (3 . ()))))
==> '(1 2 3)
(cons (quote a) (cons (quote b) (quote c)))
==> (cons '1 (cons '2 '(3 . ())))
==> '(1 2 3)

El REPL imprime este valor como una lista porque es una "lista adecuada". Cada lado derecho (cdr) es una lista, hasta la lista vacía al final, por lo que este valor sigue perfectamente la forma de la lista. El REPL asume que le gustaría ver el resultado como una lista, por lo que se imprime sin un . presente.

Tu verias '(1 2 . 3) para (pair-test (1 2 . 3)), porque así es como el REPL imprime "listas incorrectas". Si el último elemento de la cadena de pares no es la lista vacía, el valor se considera una "lista incorrecta" y se imprimirá de manera diferente:

(quote (1 . (2 . 3)))
==> '(1 2 . 3)
(cons 1 (cons 2 3))
==> '(1 2 . 3)

respondido 15 mar '12, 22:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.