Dada la siguiente función LISP eval - ¿qué se requiere para agregar defmacro?


Dada la siguiente definición de la función LISP eval - ¿qué se requiere para agregar la función defmacro? (O incluso simplemente evaluar una macro)

(defun null. (x)
      (eq x '()))

(defun and. (x y)
  (cond (x (cond (y 't) ('t '())))
        ('t '())))

(defun not. (x)
  (cond (x '())
        ('t 't)))

(defun append. (x y)
  (cond ((null. x) y)
        ('t (cons (car x) (append. (cdr x) y)))))

(defun list. (x y)
  (cons x (cons y '())))

(defun pair. (x y)
  (cond ((and. (null. x) (null. y)) '())
        ((and. (not. (atom x)) (not. (atom y)))
         (cons (list. (car x) (car y))
               (pair. (cdr x) (cdr y))))))

(defun assoc. (x y)
  (cond ((eq (caar y) x) (cadar y))
        ('t (assoc. x (cdr y)))))

(defun eval. (e a)
  (cond
    ((atom e) (assoc. e a))
    ((atom (car e))
     (cond
       ((eq (car e) 'quote) (cadr e))
       ((eq (car e) 'atom)  (atom   (eval. (cadr e) a)))
       ((eq (car e) 'eq)    (eq     (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'car)   (car    (eval. (cadr e) a)))
       ((eq (car e) 'cdr)   (cdr    (eval. (cadr e) a)))
       ((eq (car e) 'cons)  (cons   (eval. (cadr e) a)
                                    (eval. (caddr e) a)))
       ((eq (car e) 'cond)  (evcon. (cdr e) a))
       ('t (eval. (cons (assoc. (car e) a)
                        (cdr e))
                  a))))
    ((eq (caar e) 'label)
     (eval. (cons (caddar e) (cdr e))
            (cons (list. (cadar e) (car e)) a)))
    ((eq (caar e) 'lambda)
     (eval. (caddar e)
            (append. (pair. (cadar e) (evlis. (cdr e) a))
                     a)))))

(defun evcon. (c a)
  (cond ((eval. (caar c) a)
         (eval. (cadar c) a))
        ('t (evcon. (cdr c) a))))

(defun evlis. (m a)
  (cond ((null. m) '())
        ('t (cons (eval.  (car m) a)
                  (evlis. (cdr m) a)))))


(eval '(car '(a a)) )
Author: Robert Harvey, 2010-09-10

2 answers

La representación de una macro anónima es por convención una lista de la forma (macro lambda ...). Intente evaluar estos en su intérprete Lisp favorito (probado en Emacs):

> (defmacro triple (x ` " ( + , x ,x ,x))

triple

> (símbolo-función " triple)

(macro lambda (x) (\` (+ (\, x), ( \ , x), ( \ , x))))

Aunque las cosas no funcionan de esa manera en Emacs, lo único que queda por hacer es dar la adecuada semántica a tal forma. Es decir, cuando eval. ve ((macro lambda (x) EXPR) FORM), debe

  1. Reemplace cada ocurrencia de x en FORM con EXPR sin evaluar EXPR primero (a diferencia de lo que sucede en una llamada a la función);
  2. eval. el resultado de arriba.

Puede lograr esto agregando una cláusula al cond más externo en eval. que se ocupa del caso ((macro lambda ...) ...). Aquí está un prototipo crudo:

((eq (caar e) 'macro)
     (cond
      ((eq (cadar e) 'lambda)
       (eval. (eval. (car (cdddar e))
                     (cons (list. (car (caddar e)) (cadr e)) a))
              a))))

Este código solo funciona para macros de un solo argumento. Fijar eso implica escribir una función auxiliar substlis. que funciona como evlis. pero sin bucle a eval.; que se deja como un ejercicio al lector: -)

Para probar, defina cadr. como una macro así:

(defmacro cadr. (x)
  (list. 'car (list. 'cdr x)))

Después de esto tendrías{[22]]}

> (símbolo-función " cadr.)

(macro lambda (x) (list. (citar coche) (lista. (cita cdr) x)))

Puede construir una forma que aplique esto (macro lambda ...) a una expresión, y evaluar esa construcción dentro de un contexto que contiene una definición para list. (porque no es considerado primitivo por el intérprete eval.). Por ejemplo,

(let ((e '((macro lambda (x) (list (quote car) (list (quote cdr) x)))
           (cons (quote x) (cons (quote y) nil))))
      (bindings `((list ,(symbol-function 'list.)))))
  (eval. e bindings))

y

¡Tada!

 20
Author: DomQ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-10 14:05:25

Esto también es bastante bueno: https://web.archive.org/web/20120702032624/http://jlongster.com/2012/02/18/its-not-about-macros-its-about-read.html

"Puede implementar un sistema macro en 30 líneas de Lisp. Todo lo que necesitas es leer, y es fácil." https://gist.github.com/1712455

 3
Author: hawkeye,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-13 11:01:58