13.1 函数是什么?(DONE)

大体上来说,函数是一种运算规则。函数的输入称为参数,运算结果称为函数的返回值。这种计算也可以有副作用,比如修改变量的值或者修改数据的结构。纯函数是指没有任何副作用,且不受诸如机器状态或系统状态等外部因素影响,相同的输入总是返回相同的输出的函数。

在绝大多数的语言中,函数必须有自己的名称。但在Lisp中,严格来说,函数是没有名称的:函数只是一个可以和符号相关联的对象,其中相关联的符号起到了函数名称的作用。函数被指定名称后,我们通常也会称那个指代函数的符号为函数(比如,我们会说函数“car“)。在本手册中,函数名和函数对象两个概念,在不引起混淆的情况下,我们统称其为函数。

有些对象看起来和函数很像,比如特殊表达式和宏,它们都接受参数,并进行一系列的运算。但在后面,我们会解释它们与函数的区别。

这里有一些与函数以及类函数对象相关的重要术语:

lambda 表达式

使用Lisp编写的函数(严格来说,是指函数对象)。后续章节会有详细的介绍。

primitive

可以在Lisp中调用,但实际是用C实现的函数。primitive又称内置函数,或subrs。比如常见的car,append这些函数。另外所有的特殊表达式同样被视为primitives。

通常来说,一些primitive函数是构成Lisp语言的基础部分(比如car),一些提供了与操作系统交流的更底层接口,还有一些只是我们需要它运行的非常快。和其他用Lisp编写的函数不同,primitives只能通过修过C源码并重新编译Emacs的方式进行修改或增加。详情可以查阅编写Emacs Primitives章节。

special form 特殊表达式

特殊表达式也属于primitive,同样由C实现。但不同的是,特殊表达式对其参数的求值的控制和常规函数不同。特殊表达式可能只对其参数的某一部分进行求值,或者对参数用一些特殊的顺序求值,抑或是多次求值。例子有if,and,和while。详情查阅特殊表达式。

macro 宏

宏是一种使用Lisp编写的结构,用于将一个Lisp表达式转换成另一个Lisp表达式,并取代原先的那个表达式进行求值。宏给开发者提供了一种原本只有特殊表达式具有的处理问题的能力。详情查阅宏。

command 命令

可以直接由 command-execute primitive调用的对象,通常会和用户的按键绑定。详情查阅交互式调用。通常来说,命令就是一个函数。如果想用Lisp函数去实现一个命令,那么需要在函数定义中,增加interactive表达式(详情查阅定义命令)。由函数实现的命令,也可以像其他函数被Lisp表达式调用。

键盘宏(字符串和向量)同样也是命令,即使它们不是函数。详情查阅函数宏。在不引起歧义的语境下,我们称函数槽为命令的符号也为命令(详情查阅符号组成);另外,具名命令可以使用M-x调用。

closure 闭包

与lambda表达式非常相像的函数对象,区别是闭包还拥有一个词法绑定的环境。详情查阅闭包。

byte-code function 字节码函数

已经被编译器编译成字节码的函数。详情查阅字节码函数类型。

autoload object 自动加载对象

自动加载对象是真实函数的占位符。若该自动加载对象被调用,Emacs会从包含真实函数定义的文件中加载函数,然后调用。详情查阅自动加载对象。

你可以使用谓词函数 functionp 来测试某个对象是不是函数:

Function: functionp object

若object是任意类型的函数,则返回t,这里的函数同样可以作为参数传递给funcall调用。需要注意的是,functionp会对表示函数名称的符号返回t,而且对特殊表达式测试时返回nil。

我们同样可以查看任意一种类型的函数调用参数的个数:

Function:func-arity function

该函数会提供指定函数function的参数列表。返回值为一个点对(min . max),其中min表示最少参数个数,max表示最多参数个数,若函数包含&rest参数,则为符号many,若函数时特殊表达式,则为符号unevalled。

需要注意的是,该函数在某些情况下返回的值并不准确,比如:

  • 使用 apply-partially 定义的函数

  • 使用 advice-add 定义的函数

  • 拥有动态参数列表的函数

与functionp不同,接下来的三个函数并不将指代函数的符号视为函数。

Function:subrp object

(subrp 'message)            ; message is a symbol,
     ⇒ nil                 ;   not a subr object.
(subrp (symbol-function 'message))
     ⇒ t

若object为内置函数(比如Lisp primitive)则返回t

Function:byte-code-function-p object

若object为字节码函数,则返回t,比如

(byte-code-function-p (symbol-function 'next-line))
     ⇒ t

Function:subr-arity subr

该函数和func-arity很类似,但是只针对内置函数,而且不带有符号转义。当作用在非内置函数时,会抛出错误。我们推荐使用 func-arity来替代这个函数。

最后更新于