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
若object为内置函数(比如Lisp primitive)则返回t
Function:byte-code-function-p object
若object为字节码函数,则返回t,比如
Function:subr-arity subr
该函数和func-arity很类似,但是只针对内置函数,而且不带有符号转义。当作用在非内置函数时,会抛出错误。我们推荐使用 func-arity来替代这个函数。
最后更新于
这有帮助吗?