写了多年程序,突然想知道为什么函数可以连着用啊

2018-09-12 11:56:54 +08:00
 pinews
就是 a(b(c()))这样,虽然经常这样用,总觉得怪怪的,不知道在哪里是否有专门的说明?
15424 次点击
所在节点    PHP
148 条回复
greatbody
2018-09-13 11:51:08 +08:00
什么叫学了这么多年函数。这个知识是函数基础啊。数学课都教了的。
samuel37
2018-09-13 13:03:18 +08:00
感谢楼主帮我找回了自信 比心❤️
geeti
2018-09-13 13:10:00 +08:00
@molvqingtai 还真不是
pinews
2018-09-13 14:00:29 +08:00
@FrankHB
@bumz
@zagreb
函数调用是一种表达式运算符,官网确实没有,javascript 有(我也是刚看到) FrankHB 提到的那个文档更准确(可惜,英文不好,之前没见过)
既然函数调用是一种运算符,那么,a(b(c()))跟$a=$b=$c 及$a+$b+c 意义就是一样的了,这个是不是来自于结合律啊,我在 javascript 看到了,不是很明白,如果这样的话,程序语言的确是来自数学的吧。

函数表达式应该指的是将将匿名函数赋值给变量这个语句,函数是表达式,联系上下文,这里的函数是定义了一个函数,最后的表达式指的还是函数调用。

能不能所是官网的锅?

另外,applicative order 之前没接触过,看了描述虽然能有一点理解,但总体是不明白,能不能科普一下是怎么回事?
Taobin90
2018-09-13 14:08:34 +08:00
@molvqingtai 大佬对高阶函数怕是有什么误解
FrankHB
2018-09-14 00:23:10 +08:00
@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 这种更基本的概念也是乱七八糟的,我只建议把这些内容作为学有余力的阅读材料以免更加混乱。
FrankHB
2018-09-14 01:28:40 +08:00
@persimmon 你可能没注意到,题主提到的几个例子里把参数求值切开,把整个函数表达式除了参数部分的求值看作一个整体,在常见的语言中后者都是 tail context (不说 tail position 是因为这里的计算不是对象语言的某个表达式的求值的作用,而只是其中的一部分——所谓“ admistrative ” term reduction ;这没法不修改语法表达出 position )。
我觉得引入新语法强行给出对象语言表达式求值 continuation 的 position 可能看起来更乱,所以还是拿代码变换的来举例一下:
在某种元语言中可实现求值对象语言的表达式 a(b(c()))
=>
{t := c(); a(b(t))}
=>
{t := c(); u := b(t); a(u)}
※元语言中的;表示顺序求值,且求值引入的中间变量 t、u 的作用为空(这是几乎所有语言中的情况,这玩意儿不是 object macro )。
显然这里的三个函数体不需要是同时活动的。
(好吧这样一写我倒是知道为啥有人提 SSA 了,不过这里其实也不需要有 A,虽然符合 SSA 的结果。所以这里也用:=表示了。)
一般的例子里,只要多个参数就自然没有随便当成 tail call 那么方便,不然都不需要动态分配活动记录了……
cluulzz
2018-09-14 10:23:21 +08:00

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/488475

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX