因为这是显然的倒退。
函数(function) 的另一个同义词是“功能”,本来就有更高层次的抽象的意象在里面。所以编程语言发展过程中会把过程(procedure) 自觉合并到“函数”里,而不管数学上原本的定义是怎么样的。
(另一个原因是数学上的定义本来就不怎么样,混乱程度参考
en.wikipedia.org/wiki/History_of_the_function_concept 词条——看,都需要单独整个条目出来了。)
所以你所谓去函数,会被一般用户理解为去除功能上的模块化抽象。
另一方面,对有点兴趣关心不同语言设计的用户,你说的函数具体是什么,都是个问题。但是既然你用“命令”代替“函数”,那我就当作最常见高级语言里允许带变量名构成参数的那种。
而这样你就走进死胡同里了:你在对抗最常规的高级语言普遍需求——抽象。
学术一点讲,虽然我数落数学定义,但是现代意义上的真正算跟高级语言捆绑在一起的“函数”,其构造器的学名(来自λ演算)就叫“λ抽象”。这货的重要性在于,它是所有日常通用编程语言中叫“函数定义”的东西在操作语义描述中的原型,不管语言的设计者是不是意识到了这点。
为什么命名为抽象?因为它提供了把变量绑定作为形式参数的现代意义上的“函数”的普遍功能,而变量名允许用户自行随意决定而原则上不改变程序的语义稳定性(α-转换),或者说,允许定义函数的作者以决定变量名的方式夹带私货,隐藏实现。配合抽象的应用(函数调用)的结果能被作为抽象的操作数(函数参数),以此能组合出最基本的接口和实现分离提供微观上的可维护性——这是实用意义上最基本的可编程性的一部分。
因此即便原版λ抽象也不支持副作用(以之后几十年的时髦话来说,纯函数式),拿来给人编程,在很大程度上就足够比任何不提供抽象的语言好用。
相比之下,大多数传统数学家(不算整数理逻辑之类的)习惯的那种所谓的函数更适合叫“映射”,严格定义(例如通过笛卡儿积或者数学关系)上只是一种更一般意义上的函数的没多少可编程性的实现方式罢了。
完全没有限制的抽象可能会被滥用,所以也被一些用户批判,比如 FORTRAN 和 BNF 之父 J. Backus 。他在 1977 年图灵奖演说中发牢骚并提出要以所谓的 FLP(function level programming) 解决当前语言的哲学问题。这个方案的核心就是消灭抽象——带变量的函数,让所有函数回归到没有变量而通过组合的更接近传统数学上容易排除私货而更容易推理的玩意儿,所谓 point-free style ( point 就是参数名)。
但这显然没有工程意义上成功到哪去。甚至学术上也不咋地,因为计算模型上撑死就只是μ-递归函数这套,实在没多少新东西。这番推广倒是便宜了一字之差的 FP(function programming) ——而后者是显然接受甚至鼓励λ抽象的。
FLP 失败的根本原因是,禁止用户使用函数参数就是“不好用”。(考虑基本没什么人用,具体现代例子还真不太好举例,比如想想只准管道不准 xargs 之类的 shell ……)要克服 FLP 风格的抽象困难特别是不容易表达常规递归算法描述的解的问题,用户程序基本得像早期 Lisp 语言一样要发明动态的环境(实际通常不具备像λ演算一样用替换实现“调用”的条件,至少非纯函数不大行)甚至词法闭包去重新实现抽象;考虑到实现λ抽象是λ演算的语义上的工作量的 50%以上(这保守了,实际一般起码 80%,如果考虑类型系统等其它特性经常对函数定义有逻辑依赖的话),这四舍五入基本上就是自己实现一个新语言的解释器了。而 FLP 语言又不是汇编这样能容易让硬件支持来换取存在感的语言,在这里还不如直接从实现栈里一脚踹开,站茅坑不拉屎在实用上是完全不合格的。
再者,强调 point-free 也不是什么新的东西,组合子逻辑在 1950 年代早就整出来了——但也就是更早(不晚于 1940 年代)的λ演算上抠掉自由变量的缩水版整理出的(虽然组合子本身的历史可以追溯到 1920 年代)。而使用体验呢?除了纯函数式那套,比汇编还汇编(连寄存器都没)。甚至实际可用的组合子逻辑实现如 unlambda ,为了写出和“传统”语言功能等价的代码的一般方法,还得指望用户自己先构造λ抽象然后人肉编译去掉其中的具名参数。另一种路线是 APL——函数命名炸了(自行查找代码怎么写的)。
这样的语言,能被多数高级语言用户接受才有鬼了。
这里的缩水版函数(组合子),与其说是大道至简的 basic building block ,倒不如说只是一种(通过抽象这种构造器引入的)健全版函数的丐版,甚至都未必有传统数学上的映射实用(映射的描述是起码可以选配抽象的,只是形式上很不严格);毕竟计算模型上考虑语义而不仅仅是表面的语法,和组合子同等重要甚至更根本的东西多了去了。
而所谓的“命令”,不说是不是被抽象养刁了的编程语言用户接受(大部分还是非纯函数式语言的抽象,组合子都没法这样扩展),连学术上引起的兴趣都远不如组合子。
考虑历史,“命令”本质上是什么呢?其实就是因为一开始实现困难,而不那么强调组合的低级语言中间产物——命令或者说指令,早期基本就是机器操作助记符的同义词。之后即便在 FORTRAN 之类的高级语言中推广,但是增加的功能也相当抠,说白了是另一种风格的丐版函数。和组合子的丐版不同在于,它没 point-free 那么极端地拒绝使用不能作为函数组合的参数,但也没一般编程语言强调允许递归地把结果作为实际参数。结果就算不像组合子在高级语言可编程性上那么反人类(还得人肉编译才能写出多数编码),就是鸡肋中的战斗机。
至于为什么讲到 DSL 看上去更容易接受“去函数”?因为 DSL 的目标用户通常没有经过基础的编程语言训练——不但没编程语言理论(大多数程序员其实也都没有),而且缺乏任何一种支持不丐版函数的通用编程语言的学习,所以理解不了“函数”的现代内涵,会把“函数”的理解自觉停留在中学阶段那种漏洞百出的玩意儿上,更加想象不出“函数”能用到怎么灵活的程度。这样,“命令”这种看上去无关的强大的“实用”货色,才会容易被接受。
(其实内部鄙视链也是有的,比如因为解决不了 funarg 问题等实现原因而无法支持一等函数的类 ALGOL 语言和拐弯用“方法”支持自由函数的所谓面向对象语言的用户,就经常在所谓“函数式”语言的用户的火力范围之内。)
对任何有点通用目的编程语言使用经验的用户来说,对不那么丐版的函数(包括“过程”)有点体验就会食髓知味,自然回不去被强迫使用“命令”了。(这也是为什么 shell 不受很多程序员待见的原因之一;虽然讲道理 shell 的函数没那么丐,还有个原因是不容易完全写对,维护起来太作妖了。)
所以你的“微观上是函数,宏观上就自然升级到了指令”根本是外行人^n (n>=2) 的无稽之谈。
(就不说 CPU 指令到底是不是微观的问题了,反正大部分用户都不会直接碰这个去编程。)