函数真是一等公民吗?
在JavaScript中,函数是头等(first-class)对象,因为它们可以作为参数和返回值,也可以赋值给变量和属性。
初次读到“一等公民”函数的时候,我很兴奋:如果函数和其他类型的值一样,是不是意味着我可以像操作数字和字符串那样操作函数,操作代码?
可读到最后,教程也没有告诉我怎么修改函数,我感觉有些上当。
函数作为一等公民,能做的操作只有组合,就好像只能插值的字符串,没法截短,没法检视,只能沿着越变越大一路狂奔。
函数还总是与其他类型的值格格不入。
除了四则运算,还有一整个数学库用于操作数字。除了随机访问,还有一整套正则表达式用于操作字符串。那我缺的函数标准库这一块谁来补?
数字、字符串、布尔值等一等公民,无不可序列化。一些语言把列表和字典逐出了核心,但总是与JSON具备互操作性。唯独函数,要么序列化成函数名敷衍了事,要么干脆彻底不支持。
打印调试输出,跟序列化的情况差不多。要么打出个对调试毫无帮助指针地址,要么当场报错。
看来,一等公民里头还分三六九等。
如果只要允许赋值到变量,作为参数和返回值,就算一等公民的话,C语言的函数(指针)毫无疑问是一等公民。作为早期系统编程语言,C牺牲了嵌套函数换来了一等公民函数。可人们说不是,C函数不是一等公民。
函数是函数,指针是指针,这只是名字的问题。大可把“函数指针”重命名为“函数对象”,C函数就算一等公民了。
Haskell的函数不能比较相等性,因此不能作为映射键。可Haskell函数是一等中的一等。
JavaScript确实支持通过new Function
创建一个有动态源码的函数,通过.toString()
动态获取函数的源码。Python、Ruby等动态语言也有此能力。但源码借用字符串来表达,大大限制了程序处理的可行操作。
Lisp系宏是最接近、最变幻莫测的,无愧于代码即数据。但它操作的是程序代码,而不是函数。获取函数代码不是标准操作。
凡此种种函数,哪能算是一等公民——“可供调用的不透明句柄”,我是这么说的。