尽管函数通常通过 defun 定义并同时赋予名称,但有时使用显式的 lambda 表达式 —— 即 匿名函数(anonymous function) 会更为便捷。匿名函数可在任何能使用函数名的场景下生效,常被赋值给变量,或作为函数的参数使用;例如,你可以将一个匿名函数作为 function 参数传递给 mapcar,由 mapcar 将该函数应用到列表的每个元素上(see 映射函数)。相关实际应用示例,see describe-symbols example。
若要定义用作匿名函数的 lambda 表达式,应使用 lambda 宏、function 特殊形式,或 #' 读取语法:
该宏会返回一个匿名函数,其参数列表为 args、文档字符串为 doc(若有)、交互式规范为 interactive(若有),函数体由 body 给出的若干形式构成。
例如,这个宏使得 lambda 形式几乎自引用:对一个首元素(CAR)为 lambda 的表达式进行求值,得到的值与该表达式本身几乎一样:
(lambda (x) (* x x))
⇒ #f(lambda (x) :dynbind (* x x))
在词法绑定下求值时,结果是一个类似的闭包对象,其中 :dynbind 标记会被捕获的变量所替换(see 闭包)。
lambda 表达式还有一个作用:它通过将 function 作为子程序使用(见下文),告知 Emacs 求值器与字节编译器其参数是一个函数。
这个特殊形式会返回 function-object 的函数值。在很多方面,它与 quote 类似(see 引用)。但与 quote 不同的是,它同时还向 Emacs 求值器和字节编译器标记:function-object 是 “intended to be used as a function(意图作为函数使用)”。
假设 function-object 是合法的 lambda 表达式,这会产生两个效果:
当 function-object 是一个符号且代码被字节编译时,若该函数未定义或在运行时可能无法被识别,字节编译器会发出警告。
读取语法 #' 是使用 function 的简写形式。以下形式完全等效:
(lambda (x) (* x x)) (function (lambda (x) (* x x))) #'(lambda (x) (* x x))
在下面的示例中,我们定义了一个 change-property 函数,该函数接受一个函数作为第三个参数;随后定义了 double-property 函数,它通过向 change-property 传入一个匿名函数来使用该函数:
(defun change-property (symbol prop function)
(let ((value (get symbol prop)))
(put symbol prop (funcall function value))))
(defun double-property (symbol prop) (change-property symbol prop (lambda (x) (* 2 x))))
请注意,我们并未对 lambda 表达式进行引用(quote)。
如果你编译上述代码,这个匿名函数也会被编译。但假如你是通过将匿名函数作为列表进行引用(quote)的方式来构造它,情况就不同了:
(defun double-property (symbol prop) (change-property symbol prop '(lambda (x) (* 2 x))))
在这种情况下,该匿名函数会以 lambda 表达式的形式保留在编译后的代码中。即便这个列表看起来像一个函数,字节编译器也无法认定它就是函数 —— 因为编译器并不知道 change-property 意图将其用作函数。