elisp – defun vs defmacro y backquote vs list

Pregunta:

Si bien en busca excluir los usos de la list funciones a través del backquote sustitutos en defmacro s, mi intento falló cuando se combina con la let y ` let* receta, junto con el gensym función (como fuente de unintern símbolos ed, como se ilustra en otra parte ), para crear variables temporales, pero este último no es el problema.

Un MWE en ejecución [EDITADO: macroexpansión insertada] es el siguiente.

(defun w (a &optional b) ; line 1
  (let ((z (gensym)))
   `(let* ((,z (if (integerp ,b) '((,a ,b)) '((,a))))) ,z)))
    ⇒ w

(eval (w 3)) ; line 2
    ⇒ ((3))
(eval (w 3 0)) ; line 3
    ⇒ ((3 0))

La w es una defun anterior: cuando el segundo argumento opcional integerp está presente, devuelve el par como una lista " duplicada "; de lo contrario, devuelve solo el primer argumento, también dentro de dos pares de paréntesis.

Ahora viene la parte complicada: es necesario reemplazar defun con defmacro ( m por w ).

(defmacro m (a &optional b) ; line 4
  (let ((z (gensym)))
   `(let* ((,z (if (integerp ,b) `((,a ,b)) `((,a))))) ,z)))
    ⇒ m

(macroexpand (m (+ 1 2) 0)) ; line 5
    ⇒ list: Symbol's value as variable is void: a

Y también intentar devolver la evaluación de (+ 1 2) , es decir, ((3 0)) . El lazo muestra que la line #4 está defectuosa .

A continuación, utilice comillas simples, es decir, '((,a ,b)) .

(defmacro m (a &optional b) ; line 6
  (let ((z (gensym)))
   `(let* ((,z (if (integerp ,b) '((,a ,b)) '((,a))))) ,z)))
    ⇒ m

(macroexpand (m (+ 1 2) 0)) ; line 7
    ⇒ (((+ 1 2) 0))

Está bien, pero no hay evaluación del argumento: no es aceptable.

(defmacro m (a &optional b) ; line 8
  (let ((z (gensym)))
   `(let* ((,z (if (integerp ,b) (list (list ,a ,b)) (list (list ,a))))) ,z)))
    ⇒ m

(macroexpand (m (+ 1 2) 0)) ; line 9
    ⇒ ((3 0))

Finalmente, use la función de list para variar: esta vez funciona, pero hay una list más.

El problema es entonces cómo puede la line #4 mantener su forma minimalista usando comillas (traseras), de modo que la line #5 resulte como line #3 – usando defmacro versus defun . Hay un patrón ' (... dentro de' (--- . Que podría ser la causa.

Aprecia todas las respuestas. Gracias.

Respuesta:

No es necesario usar una cita inversa dentro de otra, esa es la belleza.

(defmacro m1 (a &optional b)
  (let ((z (gensym)))
    `(let ((,z (if (integerp ,b)
                   (list ,a ,b)
                 (list ,a))))
       ,z)))

Pero eso no es correcto todavía. El propósito de z no es agregar otra variable por el gusto de hacerlo, sino evitar que b sea ​​evaluado más de una vez (porque hacerlo podría tener efectos secundarios o ser costoso). No estás haciendo eso. He aquí cómo hacerlo.

(defmacro m2 (a &optional b)
  (let ((z (gensym)))
    `(let ((,z ,b))
       (if (integerp ,z)
           (list ,a ,z)
         (list ,a)))))

Esto demuestra la diferencia:

(let ((v 1)) (m1 1 (cl-incf v))) => (1 3)
(let ((v 1)) (m2 1 (cl-incf v))) => (1 2)

No tiene que hacer lo mismo para a porque, aunque aparece dos veces, solo se evalúa una aparición.

Leave a Comment

Your email address will not be published.

Scroll to Top

istanbul avukat

-

web tasarım