如何编写简单的LISP宏来返回指定表单的输出(从表单列表中)?

时间:2017-02-21 13:17:45

标签: macros lisp

我是LISP的新手,想要了解,如何编写LISP宏代码,它会评估所有表单,但只返回一个指定表单的输出,其中要返回的表单可以在宏内指定,也可以是用户提供的输入

我使用了以下宏,它返回第二个表单的输出。但它似乎不正确,因为它似乎没有评估第一种形式,我想指定要评估的两种形式中的哪一种。

(defmacro testcode()(+ 3 4)(+ 5 6))

(macroexpand-1(testcode))

11 NIL

1 个答案:

答案 0 :(得分:1)

宏是语法抽象或语法加糖。 testcode在宏扩展时进行计算,因此您不能指望多次计算表单,而(testcode)与“代码”11同义。为了说明这个让它产生副作用:

(defmacro testcode ()
  (print "expanding testcode")
  (+ 3 4)  ; dead code. Never gets used
  (+ 5 6)) 

(defun test ()
  (testcode))
; prints "expanding testcode"

(test)
; ==> 11 (doesn't print anything)

(test)
; ==> 11 (still doesn't print anything, Why?)

(disassemble 'test)
; ==>
; 0     (const 0)      ; 11
; 1     (skip&ret 1)

所以test字面上与(defun (test) 11)相同。

那么宏是什么?好吧,如果你写了这个并注意到有一种模式:

(let ((it (heavy-cpu-function var)))
  (when it 
      (do-something-with-it it)))

你可以说这是我创建语法的东西:

(defmacro awhen (predicate-expression &body body)
  `(let ((it ,predicate-expression))
     (when it
       ,@body)))

(macroexpand-1 '(awhen (heavy-cpu-function var)
                  (do-something-with-it it)))
; ==>
; (let ((it (heavy-cpu-function var))) 
;   (when it 
;     (do-something-with-it it)))

因此,不是编写第一个,而是使用awhen而Common Lisp将其更改为第一个。你使用了很多宏,因为Common Lisp中的很多语法都是宏:

(macroexpand-1 '(and (a) (b) (c)))
; ==> 
; (cond ((not (a)) nil) 
;       ((not (b)) nil) 
;       (t (c)))

(macroexpand-1 '(cond ((not (a)) nil) 
                      ((not (b)) nil) 
                      (t (c)))
; ==>
; (if (not (a)) 
;     nil 
;     (if (not (b)) 
;         nil 
;         (c)))