2010-09-10 52 views
24

鑑於LISP評估函數的以下definition - 添加defmacro函數需要什麼? (甚至只是評估宏)鑑於以下LISP評估函數 - 添加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

這是另一種[宏觀實現方法] [1]。 [1]:http://stackoverflow.com/questions/3465868/how-to-implement-a-lisp-macro-system/10363040#10363040 – hawkeye 2012-04-28 11:26:49

回答

20

匿名宏的表示是通過約定的形式(macro lambda ...)的列表。嘗試evaling這些在你最喜歡的Lisp解釋(在Emacs中進行測試):

>(defmacro三聯(X)`(+ X,X,X))

三重

>(符號函數「三重)

(宏拉姆達(X)(\`(+(\,X)(\,X)(\,X))))

儘管事情在Emacs中並不是那樣工作,但唯一要做的就是給這樣的表單提供足夠的語義。也就是說,當eval.看到((macro lambda (x) EXPR) FORM),它必須

  1. 更換的x每一次出現在FORMEXPR評估EXPR第一(而不是在函數調用會發生什麼);
  2. eval.以上的結果。

您可以通過添加在eval.一個條款,最外面的cond,與((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)))) 

此代碼僅適用於單參數宏。修復涉及編寫一個像evlis.一樣工作但沒有循環到eval.的輔助功能substlis.;被留下作爲一個練習讀者:-)

要進行測試,確定cadr.作爲正是如此宏:

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

這之後,您將有

>(符號功能「 CADR)

(宏拉姆達(X)(名單。(汽車報價)(列表(報價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)) 

Ÿ

田田!

+1

幹得漂亮! (爲了簡潔起見,添加了括號。) – 2010-09-11 23:10:02

+0

感謝@DomQ - 但是我嘗試瞭解決方案中的兩個LISP環境,給了一個stackoverflow。您的解決方案可能存在問題嗎? – hawkeye 2010-09-12 01:13:09

+1

「關聯」中存在一個錯誤。導致溢出,嘗試評估(assoc。'x nil)。您可以通過向「assoc。」的cond塊添加一個子句來修復它:((null。y)'())。我向Paul Graham發送了這封電子郵件,他說這不是一個錯誤,因爲原作者John McCarthy不關心不正確的程序(即那些引用「eval」中的自由變量的程序)。無論如何,這可能是你觀察到的堆棧溢出只是另一個問題的症狀。嘗試使用http://paste.lisp.org/+2GC7(包含「assoc。」修復程序和我的解決方案,用Emacs 22和librep.sf.net進行測試)。 – DomQ 2010-09-13 07:50:12