首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
宝塔
V2EX  ›  PHP

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

  •  
  •   pinews · 2018-09-12 11:56:54 +08:00 · 12742 次点击
    这是一个创建于 434 天前的主题,其中的信息可能已经有所发展或是发生改变。
    就是 a(b(c()))这样,虽然经常这样用,总觉得怪怪的,不知道在哪里是否有专门的说明?
    第 1 条附言  ·  2018-09-12 22:07:22 +08:00

    不是引站,我自己也经常用来着,有次看到回调函数突然想起这个,当然和回调函数是不一样的,却不知道为什么能用,看说明上说函数参数可以为任何类型,但没找到说可以放个函数进去,这些基础知识不知道在哪里学,比如

    echo md5(10>1 ? 10 : 1);
    

    竟然也可以,总之,学习到很多,谢谢大家。

    第 2 条附言  ·  2018-09-13 16:35:56 +08:00
    感谢博学多识的 FrankHB,他给出了 php 的设计说明书:
    https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#function-call-operator

    噫吁嚱!危乎高哉!
    148 回复  |  直到 2018-09-14 10:23:21 +08:00
    1  2  
        101
    pinews   2018-09-12 23:21:44 +08:00
    @zagreb javascript 里面说了 函数调用是一种运算类型,和成员访问、new、数组是同一级别的。
        102
    molvqingtai   2018-09-13 02:15:12 +08:00 via Android
    这不就是普通的高阶函数吗?
        103
    PythonAnswer   2018-09-13 02:42:25 +08:00
    第一次学的时候, 就连着用的, 没有人跟我一样?
        104
    FrankHB   2018-09-13 08:10:25 +08:00   ♥ 6
    那么点基础 PL 问题怎么各路妖魔鬼怪都出来了……
    一个 applicative order 有这么难找么?
    好吧,这几十年搞语言的平均水平是比较低,大多就会瞎耦合特性不会复用成熟概念,拉低用户眼界也没办法,学校又不教你历史倒是容易懵逼。。。但是蒙也有点准头吧……还离谱得很那啥。(像 BS 老头搞不清 currying 和 partial application 的区别这种也就算了……)
    @est 这里从头到尾都是 unary 的,如何想到跟 currying 有几毛钱关系的???
    @mengzhuo 都没要求保存活动记录状态,直接死 reduction 都过得去,有没有栈有什么区别……?还 SSA ……您倒是介绍一下连个 binding 都搞不进去的构造里哪来能 A 的东西?实在想象不出这个例子里考虑了会有啥区别。
    @jmc891205 @bumz 跟一般的数学还真不那么一样,数学因为 pure 反而不计较 normal order 还是 applicative order 什么的幺蛾子。
    @forblackking molvqingtai 哪里看出的高阶函数?
    @misaka19000 @jianleer 谁规定函数调用非得跟栈扯上关系的?
    @persimmon 好吧,非得跟栈有一腿是吧……但这例子里一坨 tail call 凭什么就得加深……
    @XXneet 跟有没有类型有几毛钱关系? UTLC 活该哭晕在厕所咯?
    @zagreb 请避免“函数表达式”这种数学过头而引起误导的说法。这种说法中求值过程是被忽略的,只关心求值结果,暗示替换没有副作用而不改变语义。这对大多数语言根本不适用。另外,至少还得分清函数作为表达式和函数调用作为表达式的区别。
    @laqow 不巧,传统 LISP 的 application 外面还要套(),并不长得这个样子;还有各种 special form 开洞。
    @zmj1316 C++当然也有这规矩,[intro.execution]/11。
        105
    killerv   2018-09-13 08:18:15 +08:00
    这是在黑 PHP
        106
    FrankHB   2018-09-13 08:24:39 +08:00   ♥ 2
    > 却不知道为什么能用

    PHP 是吧。

    https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#function-call-operator

    > An argument can be any value. In a function call, callable-expression is evaluated first, followed by each expression in the order left-to-right.

    典型的 leftmost innermost 经典版 applicative order 了。
        107
    laoyuan   2018-09-13 08:35:49 +08:00
    今年下半年黑 PHP 最狠的一次
        108
    laoyuan   2018-09-13 08:36:19 +08:00   ♥ 2
    多少人抬头看了看节点,一颗心就放下了
        109
    tourist2018   2018-09-13 08:45:55 +08:00
    @laoyuan #108 哈哈
        110
    xiandao7997   2018-09-13 08:51:05 +08:00 via iPhone
    @molvqingtai 这个不是高阶函数,传的是值不是 function..
        111
    VeryZero   2018-09-13 08:58:14 +08:00
    参数其实是函数运算完的结果,为啥不能连着。。
        112
    andyliwrldk   2018-09-13 09:01:42 +08:00
    柯里化和反柯里化
        113
    CoderEQ   2018-09-13 09:03:00 +08:00 via Android
    v2 再一次刷新我的。。。。
        114
    vegito2002   2018-09-13 09:06:38 +08:00   ♥ 1
    这个帖子不知道暴露了多少只会甩 buzzword 的"大佬"
        115
    lihongjie0209   2018-09-13 09:07:29 +08:00
    @vegito2002 笑看这些人
        116
    FakeLeung   2018-09-13 09:11:47 +08:00
    日常黑 PHP (1/1)
        117
    DavidNineRoc   2018-09-13 09:12:59 +08:00
    楼主这表达能力不行呀。
    连着用至少也是这样
    a()->b()->c();
    你这个只是省略几个变量的写法就不行了。
    这多年怕不是在写易语言吧 >_>
        118
    DavidNineRoc   2018-09-13 09:13:39 +08:00
    不好意思,我没看到 PHP
        119
    wotemelon   2018-09-13 09:21:36 +08:00
    @laoyuan 哈哈哈,看了一下是 php,默默返回了
        120
    blackguess   2018-09-13 09:23:09 +08:00
    因为编译器在编译的时候有考虑过这种情况吧
        121
    DOLLOR   2018-09-13 09:46:57 +08:00
    看了附言,明白了,楼主是完全不懂得“返回值”这种东西。
        122
    aa514758835   2018-09-13 09:56:46 +08:00
    函数的返回值作为函数参数,就等于是链式编程
        123
    ys0290   2018-09-13 09:57:59 +08:00 via iPhone
    还可以 a(a(a(a())))
        124
    gamecreating   2018-09-13 10:03:41 +08:00
    多年程序 ......你看样子还没入门...
    没学过 C 吧?
        125
    luofan004   2018-09-13 10:09:21 +08:00
    感觉楼主开始怀疑人生了。。
        126
    yufpga   2018-09-13 10:22:16 +08:00
    推荐两本书:《深入理解计算机系统》,《深入理解程序设计:使用 Linux 汇编语言》。啃这些东西都需要花些时间,多的不说,免得被楼上那些个“大佬”嘲笑。
        127
    cyspy   2018-09-13 10:33:35 +08:00
    这个帖子下面扯各种高级特性的大佬们估计现在都想抽自己的脸。这段代码简单到,无非就是 c 的返回值传给 b 而已
        128
    bumz   2018-09-13 10:41:10 +08:00
    @FrankHB #104 数学确实不计较 applicative order 和 normal order 什么的,毕竟数学诞生比 PL 早几千年,函数的诞生也比 PL 早几百年

    然而题主问为什么可以这样用,不得不说,f(g(h(x))) 这种写法还是来自数学,而数学中它的合理性则来自等式的基本性质
        129
    persimmon   2018-09-13 10:42:54 +08:00
    @FrankHB 只不过是在拿参数的位置调用了别的函数(新的过程调用),这里压根就不是个 tail position ;再说我觉你不过是在表达一个主观的 syntax 喜好的问题,为什么要上升到 semantic 层面呢?
        130
    zsdroid   2018-09-13 10:44:20 +08:00
    > 这些基础知识不知道在哪里学
    我来告诉你,这些基础知识从小学里学,知识点是,四则运算。
    `2*(1+2)`,2 不是与`(`相乘,而是与`(1+2)`的返回值相乘。
        131
    zagreb   2018-09-13 10:46:18 +08:00
    @FrankHB #104 多谢指正
        132
    bumz   2018-09-13 10:47:44 +08:00
    提栈的,applicative order 和栈还真的没什么关系

    栈不过是实现 applicative order 的其中一种辅助工具而已,在 concurrency 环境中一样可以 applicative order,但是栈就用不了了
        133
    wizardforcel   2018-09-13 10:49:21 +08:00
    因为词法是可以递归定义的啊,func(...) 接受表达式(的逗号分隔列表),它自己也算作表达式。
        134
    persimmon   2018-09-13 10:51:21 +08:00
    @FrankHB (前面那一条回复有误,请忽略)不过是在拿参数的位置调用了别的函数(新的过程调用),这里压根就不是个 tail position ;再说我觉得楼主不过是在表达一个主观的 syntax 喜好的问题,但上升到 semantic 层面明显没必要
        135
    zagreb   2018-09-13 10:54:06 +08:00
    php 文档 Expressions 章节写到“ Slightly more complex examples for expressions are functions.”和“ Functions are expressions with the value of their return value.”
    Function arguments 章节写到“ Information may be passed to functions via the argument list, which is a comma-delimited list of expressions.”
    所以我的理解是 函数调用表达式可以作为函数的参数,用以解答楼主的问题
        136
    Mutoo   2018-09-13 11:08:26 +08:00
    语法树和表达式求值,LZ 需要补一下编译原理。
        137
    bigeast   2018-09-13 11:11:27 +08:00
    @deljuven 看你一本正经地引用 Wikipedia,你自己都没看吧。看了的话就知道楼主说的跟柯里化一点关系都没有。

    45,53,70,78,92,同意。

    v2 的水平真低。
        138
    ywlvs   2018-09-13 11:30:56 +08:00
    我一直遵循着老师的教诲:有括号,先算括号里的
        139
    lancelock   2018-09-13 11:39:47 +08:00
    看来我是太高估 v2 的水平了,就一个最基本的返回值都能扯上什么函数式编程。夸夸其谈,不知所云
        140
    Roooooys   2018-09-13 11:47:13 +08:00
    @lancelock 哈哈
        141
    greatbody   2018-09-13 11:51:08 +08:00
    什么叫学了这么多年函数。这个知识是函数基础啊。数学课都教了的。
        142
    samuel37   2018-09-13 13:03:18 +08:00
    感谢楼主帮我找回了自信 比心❤️
        143
    geeti   2018-09-13 13:10:00 +08:00
    @molvqingtai 还真不是
        144
    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 之前没接触过,看了描述虽然能有一点理解,但总体是不明白,能不能科普一下是怎么回事?
        145
    Taobin90   2018-09-13 14:08:34 +08:00
    @molvqingtai 大佬对高阶函数怕是有什么误解
        146
    FrankHB   2018-09-14 00:23:10 +08:00   ♥ 2
    @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 这种更基本的概念也是乱七八糟的,我只建议把这些内容作为学有余力的阅读材料以免更加混乱。
        147
    FrankHB   2018-09-14 01:28:40 +08:00   ♥ 1
    @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 那么方便,不然都不需要动态分配活动记录了……
        148
    cluulzz   2018-09-14 10:23:21 +08:00
    1  2  
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   3392 人在线   最高记录 5043   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.3 · 28ms · UTC 04:35 · PVG 12:35 · LAX 20:35 · JFK 23:35
    ♥ Do have faith in what you're doing.