2010-09-10 8 views
24

Dado el siguiente definition de la función de evaluación de LISP, ¿qué se necesita para agregar la función defmacro? (O incluso evaluar una macro)Dada la siguiente función eval de LISP: ¿qué se necesita para agregar defmacro?

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

Esta es otra [forma de abordar la implementación macro] [1]. [1]: Muy bien http://stackoverflow.com/questions/3465868/how-to-implement-a-lisp-macro-system/10363040#10363040 – hawkeye

Respuesta

20

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

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

triples

> (triple símbolo-function')

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

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

  1. reemplazar cada aparición de x en FORM con EXPRsin evaluar EXPR primero (a diferencia de lo que ocurre en una llamada de función);
  2. eval. el resultado de lo anterior.

Esto se puede conseguir mediante la adición de una cláusula al exterior cond en eval. que se ocupa del caso ((macro lambda ...) ...). Aquí hay 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. La reparación implica la escritura de una función auxiliar substlis. que funciona como evlis. pero sin bucle a eval.; que se deja como ejercicio para el lector :-)

Para probar, definir cadr. como una macro de esta manera:

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

Después de esto tendría

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

(macro lambda (x) (lista. (presupuesto sin ningún compromiso) (lista. (CDR cita) x)))

Puede construir un formulario que aplique este (macro lambda ...) a una expresión y evaluar esa construcción dentro de un contexto que contenga una definición para list. (porque no se considera 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!

+1

hecho! (Se agregó entre paréntesis para evitar la brevedad). –

+0

Gracias @DomQ, pero los dos entornos LISP en los que intenté su solución dieron un stackoverflow. ¿Es posible que haya un problema en tu solución? – hawkeye

+1

Hay un error en "assoc". causando el desbordamiento, intente evaluar (assoc. 'x nil). Puede solucionarlo agregando una cláusula al bloque cond de "assoc." Que dice: ((null. Y) '()). Envié un correo electrónico a Paul Graham sobre esto, él dice que esto no es un error, ya que al autor original John McCarthy no le importaban los programas incorrectos (es decir, los que hacen referencia a las variables libres en "eval"). De todos modos, es posible que el desbordamiento de la pila que observas sea solo un síntoma de otro problema. Pruebe con http://paste.lisp.org/+2GC7 (contiene tanto el arreglo "assoc." Como mi solución a su pregunta; probado con Emacs 22 y librep.sf.net). – DomQ

Cuestiones relacionadas