@
bumz f(g(h(x)))的语法确实来自传统的数学。
不过这里的问题主要是语义问题。(要是觉得问题的核心是为啥 syntactically well-formed ……就算 a(b(c()))“这样”在不少语言中都长得差不多,各种语言的具体规则也都不完全一样啊……没啥好说了。)求值策略的差异问题是在 LC 上开始展开搞的(或者说注意到有必要严格区分),这个严格来说还是数学,不过已经不是传统的数学了。
@
persimmon 我还真不同意这就是个主观的 syntax 喜好的问题。其它的一些问题看来也得一并澄清一下。
首先,跟我上面提的一样,问题的核心根本就不应该是 syntax 的问题。求值的规则基本上在各个语言的 spec (包括这里的 PHP )里都算 semantics rule 而不是 syntactic rule。因为现时几乎所有 PL 的 spec 都不会通过指定一个 formal model 来描述 conformance,所以只能特别给出独立于代码构造的单独规则。
其次,使用什么样的求值规则是语言设计者意义上的主观问题,但 spec 写出来以后就是客观的东西。这里提到的 PHP 也好其它语言也好,我都不记得在 spec 里通过描述实现需要明确分配栈帧来定义程序行为。(都不这么说倒是正常的,麻烦,不容易精确,还会限制优化。)
第三,注意我在提 tail call 时的上下文:反对“栈加深”的说法。这是一个反例,而不是全称论述。
严格来讲,在支持表达 tail call 的语言中,哪里是 tail position 是具体语言的 spec 指定的;但这种规则本质上是为了约束 conformance 才存在的。缺乏这种规则并不表示被语言描述的计算就不具有这种一般特征。当然,不是说没有反例——比如 non-trivial dtor 和 contract 这类隐藏另外的 effect 的情况,算作 tail position 可能直接违反行为等价的其它语言规则。这样的例外不是我之前提的情况。
第四,退一万步讲,就算必须给过程调用分配资源,不限定具体语言实现,活动记录也未必得是栈的形式。
另外补充一下,数学意义上的函数和某些语言中的函数类比,但最好别指望能精确替代;具体语言中什么东西能管叫函数,保证了什么性质,还真都挺乱的。能区分出 applicative order 的 term 也好 expression 也好,在这个问题上都比笼统的“函数”概念精确得多——数学上的“函数”原来可完全不在乎这种问题。就算不管这个,函数这个概念在传统数学中的水就很深,维基上专门还有一个条目讲变迁历史:
https://en.wikipedia.org/wiki/History_of_the_function_concept。考虑到连 variable 这种更基本的概念也是乱七八糟的,我只建议把这些内容作为学有余力的阅读材料以免更加混乱。