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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://emacs-lisp.ivory.cafe/han-shu/13.1-han-shu-shi-shen-me-done.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
