我是LISP的新手,想要了解,如何编写LISP宏代码,它会评估所有表单,但只返回一个指定表单的输出,其中要返回的表单可以在宏内指定,也可以是用户提供的输入
我使用了以下宏,它返回第二个表单的输出。但它似乎不正确,因为它似乎没有评估第一种形式,我想指定要评估的两种形式中的哪一种。
(defmacro testcode()(+ 3 4)(+ 5 6))
(macroexpand-1(testcode))
11 NIL
答案 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)))