Учитывая следующую функцию LISP eval - что требуется для добавления defmacro? - PullRequest
26 голосов
/ 10 сентября 2010

Учитывая следующее определение функции LISP eval - что требуется для добавления функции 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)) )

Ответы [ 2 ]

21 голосов
/ 10 сентября 2010

Представление анонимного макроса по соглашению представляет собой список вида (macro lambda ...).Попробуйте проверить их в своем любимом интерпретаторе Lisp (проверено в Emacs):

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

тройной

> (символ-функция 'тройной)

(макрос лямбда (x) (\ `(+ (\,x) (\, x) (\, x))))

Хотя в Emacs все работает не так, остается только дать адекватную семантику такойформа.То есть, когда eval. видит ((macro lambda (x) EXPR) FORM), он должен

  1. Заменить каждый случай x в FORM на EXPR без , сначала оценивая EXPR(в отличие от того, что происходит при вызове функции);
  2. eval. результат выше.

Этого можно добиться, добавив предложение к самому внешнему cond вeval., что касается дела ((macro lambda ...) ...).Вот грубый прототип:

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

Этот код работает только для макросов с одним аргументом.Исправление включает в себя написание вспомогательной функции substlis., которая работает как evlis., но без зацикливания на eval.;это оставлено в качестве упражнения для читателя: -)

Для проверки определите cadr. как макрос следующим образом:

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

После этого вы получите

> (символьная функция 'cadr.)

(макрос lambda (x) (list. (Quote car) (list. (Quote cdr) x)))

Вы можете создать форму, которая применяет это (macro lambda ...) к выражению, и оценить эту конструкцию в контексте, который содержит определение для list. (поскольку интерпретатор eval. не считает его примитивным).).Например,

(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

Тада!

3 голосов
/ 07 ноября 2012

Это также довольно хорошо: https://web.archive.org/web/20120702032624/http://jlongster.com/2012/02/18/its-not-about-macros-its-about-read.html

"Вы можете реализовать макросистему в 30 строках Lisp. Все, что вам нужно, это прочитать, и это легко."https://gist.github.com/1712455

...