一个装饰基本上是一个功能。
Common Lisp中的示例:
(defun attributes (keywords function)
(loop for (key value) in keywords
do (setf (get function key) value))
function)
在上面的函数中是一个符号(它将由返回DEFUN
),我们将属性放在符号的属性列表中。
现在我们可以围绕函数定义编写它:
(attributes
'((version-added "2.2")
(author "Rainer Joswig"))
(defun foo (a b)
(+ a b))
)
如果要像在Python中那样添加精美的语法,请编写一个reader宏。Reader宏允许我们在s-expression语法级别进行编程:
(set-macro-character
#\@
(lambda (stream char)
(let ((decorator (read stream))
(arg (read stream))
(form (read stream)))
`(,decorator ,arg ,form))))
然后我们可以写:
@attributes'((version-added "2.2")
(author "Rainer Joswig"))
(defun foo (a b)
(+ a b))
Lisp 阅读器的阅读内容如下:
(ATTRIBUTES (QUOTE ((VERSION-ADDED "2.2")
(AUTHOR "Rainer Joswig")))
(DEFUN FOO (A B) (+ A B)))
现在,我们在Common Lisp中有了一种装饰器形式。
结合宏和阅读器宏。
实际上,我会使用宏而不是函数在实际代码中进行上述翻译。
(defmacro defdecorator (decorator arg form)
`(progn
,form
(,decorator ,arg ',(second form))))
(set-macro-character
#\@
(lambda (stream char)
(declare (ignore char))
(let* ((decorator (read stream))
(arg (read stream))
(form (read stream)))
`(defdecorator ,decorator ,arg ,form))))
上面的用法与相同的阅读器宏相同。优点是Lisp编译器仍然将其视为所谓的顶层表单 -* file编译器专门处理顶层表单,例如,将有关它们的信息添加到编译时环境中。在上面的示例中,我们可以看到宏会查看源代码并提取名称。
Lisp 阅读器将上面的示例读取为:
(DEFDECORATOR ATTRIBUTES
(QUOTE ((VERSION-ADDED "2.2")
(AUTHOR "Rainer Joswig")))
(DEFUN FOO (A B) (+ A B)))
然后将宏扩展为:
(PROGN (DEFUN FOO (A B) (+ A B))
(ATTRIBUTES (QUOTE ((VERSION-ADDED "2.2")
(AUTHOR "Rainer Joswig")))
(QUOTE FOO)))
宏与阅读器宏有很大不同。
宏获取传递的源代码,可以执行任何所需的操作,然后返回源代码。输入源不需要是有效的Lisp代码。它可以是任何东西,也可以写成完全不同的东西。然后,结果必须是有效的Lisp代码。但是,如果生成的代码也使用宏,则嵌入在宏调用中的代码的语法可能又是另一种语法。一个简单的例子:可以编写一个数学宏,该宏可以接受某种数学语法:
(math y = 3 x ^ 2 - 4 x + 3)
该表达式y = 3 x ^ 2 - 4 x + 3
不是有效的Lisp代码,但是宏可以例如解析它并返回有效的Lisp代码,如下所示:
(setq y (+ (* 3 (expt x 2))
(- (* 4 x))
3))
Lisp中还有许多其他宏的用例。