宏
求值
eval:接收一个表达式,将其求值并返回。
eval缺点:
1.效率低,eval处理的是原始列表,要不当下编译它,或用直译器求值。这两种方法都比执行编译过来的代码慢。
2.表达式在没有词法语境的情况下被求值。如:在let中调用eval,传给eval的表达式无法参照由let设置的变量。
eval主要的作用是作为lisp的概念模型。
函数coerce和compile可将列表转成代码。
如:传给coerce一个lamda表达式,将其成为函数。
宏
宏是通过转换而实现的操作符。通过说明一个调用应该要翻译成什么,来定义一个宏,这种翻译称为宏展开。宏展开是编译器自动完成的。
defmacro:定义一个宏
格式:defmacro 宏名称 应用到展开式的参数列表 宏主体(展开式)
如:(defmacro nil! (x)
(list 'setf x nil))
macroexpand:用于展开宏,返回一个宏展开式
反引号
反引号读取宏,使从模板构建列表成为可能。反引号为键盘1的左边的键位 ` 。且为半角输入,即英文输入状态。
单引号可保护其参数不被求值。
反引号的优点:在一个反引号表达式中,可用逗号(,)和@来重启求值。即:在一个反引号表达式中,在一个符号前加逗号的话,则此符号会被求值。@和逗号类似,若在符号前加,且此符号为列表时,则会将列表展开
如:逗号例子:
(setf a 1 b 2)
`(a is ,a and b is ,b)→(A IS 1 AND B IS 2)
@例子:
(setf lst '(a b c))
`(lst is ,lst)→(LST IS (A B C))
`(lst's elements are ,@lst)→(LST'S ELEMENTS ARE A B C)
如:
(defmacro while (test &rest body)
`(do ()
((not ,test))