13.1 什么是函数?

从一般意义上讲,函数是一种根据被称为 参数(arguments) 的输入值来执行计算的规则。计算的结果称为该函数的 值(value)返回值(return value)。计算过程也可能产生副作用,例如永久更改变量的值或数据结构的内容(see Definition of side effect)。纯函数(pure function) 是指这样一类函数:它不仅没有副作用,而且对于相同的参数组合,无论外部因素(如机器类型、系统状态)如何,始终返回相同的值。

在大多数编程语言中,每个函数都有名称。但在 Lisp 中,严格意义上的函数本身是没有名字的:它是一个对象,可以可选地与一个符号(如 car)关联,由该符号充当函数名。See 函数命名。当一个函数被赋予名称后,我们通常也将该符号直接称作 “函数(function)” (例如我们说 “car 函数”)。在本手册中,函数名与函数对象本身之间的区别通常并不重要,但在必要时我们会明确区分。

某些类似函数的对象,称为 特殊形式(special forms)宏(macros), 它们也接受参数来执行计算。 但正如后文所述,在 Emacs Lisp 中它们不被视为函数。

以下是函数及类函数对象的重要术语:

lambda expression

用 Lisp 语言编写的函数(严格意义上的函数,即函数对象)。 下一节将会介绍这些内容。 See Lambda 表达式.

primitive

可以从 Lisp 中调用,但实际是用 C 语言编写的函数。原语也被称为 内置函数(built-in functions)subr(子例程)。例如 carappend 这类函数都属于原语。此外,所有特殊形式(见下文)也都被视为原语。

一个函数之所以被实现为原语,通常是因为它是 Lisp 的核心基础(如 car),或是需要为操作系统服务提供底层接口,又或是需要具备很高的运行效率。与用 Lisp 定义的函数不同,原语只能通过修改 C 语言源码并重新编译 Emacs 来修改或添加。参见 Writing Emacs Primitives

special form

一种类似函数的原语,但不会按常规方式对所有参数求值。它可能只对部分参数求值,或以非常规顺序求值,或是对参数多次求值。例如 ifandwhile。See 特殊形式

macro

一种在 Lisp 中定义的语法结构,它与函数的区别在于:宏会将一个 Lisp 表达式转换为另一个表达式,然后对新表达式求值,而非对原表达式直接求值。宏让 Lisp 程序员能够实现特殊形式才能做到的各类功能。See

command

可以通过 command-execute 原语调用的对象,通常是因为用户键入了 绑定(bound) 到该命令的按键序列。See Interactive Call。命令通常是函数;如果该函数是用 Lisp 编写的,可在函数定义中通过 interactive 形式将其变为命令 (see Defining Commands)。作为函数的命令同样可以在 Lisp 表达式中调用,与普通函数无异。

键盘宏(字符串和向量)虽然不是函数,也属于命令。See Keyboard Macros。如果一个符号的函数单元中存放着命令,我们就称该符号为命令(see 符号的组成)。这类 命名命令(named command) 可以通过 M-x 调用。

closure

一种与 lambda 表达式十分相似的函数对象,区别在于它还封装了词法变量绑定的环境。 See 闭包

byte-code function

经过字节编译器编译后的函数。 See 闭包函数类型

autoload object

作为真实函数的占位符。当调用该自动加载对象时, Emacs 会先加载包含真实函数定义的文件,随后调用这个真实函数。 See 自动加载

你可以使用 functionp 函数来检测一个对象是否为函数:

Function: functionp object

object(对象)是任意类型的函数(即可以传递给 funcall 函数调用), 该函数返回 t。需注意:对于作为函数名的符号,functionp 返回 t; 对于作为宏或特殊形式的符号,functionp 返回 nil

object 不是函数,该函数通常返回 nil。 但函数对象的表示形式较为复杂,出于效率考量,在极少数情况下, 即便 object 并非函数,该函数也可能返回 t

你也可以获取任意函数预期接收的参数数量:

Function: func-arity function

该函数提供指定 function(函数)的参数列表相关信息。 返回值为一个点对(cons cell),格式为 (min . max): 其中 min 是参数的最小数量; max 则为参数的最大数量——若函数包含 &rest 参数,max 为符号 many; 若 function 是特殊形式,max 为符号 unevalled

需注意,该函数在部分场景下可能返回不准确的结果,例如以下情况:

  • 使用 apply-partially 定义的函数(see apply-partially)。
  • 通过 advice-add 为其添加了建议的函数(see 为命名函数添加建议)。
  • 在代码逻辑中动态确定参数列表的函数。

functionp 不同,后续这些函数 不会 将符号视为其对应的函数定义。

Function: subrp object

object(对象)是内置函数(即 Lisp 原语),该函数返回 t

(subrp 'message)            ; message is a symbol,
     ⇒ nil                 ;   not a subr object.
(subrp (symbol-function 'message))
     ⇒ t
Function: byte-code-function-p object

object(对象)是字节码函数,该函数返回 t。示例如下:

(byte-code-function-p (symbol-function 'next-line))
     ⇒ t
Function: compiled-function-p object

object 是非 ELisp 源码形式的函数对象(而是类似机器码或字节码的形式), 该函数返回 t。更具体地说,当函数满足以下任一条件时,该函数返回 t: 内置函数(也称为 “原语(primitive)” ,see 什么是函数?)、 字节编译函数(see 字节编译)、 原生编译函数(see Lisp 本地代码编译), 或从动态模块加载的函数(see Emacs 动态模块)。

Function: interpreted-function-p object

object(对象)是解释型函数,该函数返回 t

Function: closurep object

object 是闭包(一种特定类型的函数对象),该函数返回 t。 目前,所有字节码函数和所有解释型函数均以闭包形式实现。

Function: subr-arity subr

该函数的功能与 func-arity 类似,但仅适用于内置函数, 且不会进行符号间接解析。若传入非内置函数,该函数会触发错误。 我们建议优先使用 func-arity 而非此函数。

Function: cl-functionp object

该函数与 functionp 功能类似,区别在于: 对于列表和符号类型的对象,该函数会返回 nil

Function: primitive-function-p object

object(对象)是用 C 语言编写的内置原语(see 原语函数类型), 该函数返回 t。需注意:特殊形式会被明确排除在外,因为它们并非函数。 若你需要同时识别特殊形式,请使用 subr-primitive-p 函数。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike