# 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来替代这个函数。
