写了多年程序,突然想知道为什么函数可以连着用啊 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
pinews
V2EX    PHP

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

  •  
  •   pinews 2018-09-12 11:56:54 +08:00 16622 次点击
    这是一个创建于 2586 天前的主题,其中的信息可能已经有所发展或是发生改变。
    就是 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  
    est
        1
    est  
       2018-09-12 11:57:46 +08:00   2
    咖喱化(科里化)?
    javaWeber
        2
    javaWeber  
       2018-09-12 12:00:06 +08:00   4
    从内向外,函数返回的结果,作为参数使用呗。。
    deston
        3
    deston  
       2018-09-12 12:02:59 +08:00   3
    2 楼上说的很清楚了,我来看看楼下怎么说
    zn
        4
    zn  
       2018-09-12 12:06:46 +08:00 via iPhone   1
    函数调用得到的就是一个值,跟一个普通的 1 在本质上没什么区别,都是堆栈上的一个条目而已。
    Fairy1128
        5
    Fairy1128  
       2018-09-12 12:06:55 +08:00   2
    函数的结果作为参数传递给另一个函数 很正常啊 又不是 callback 更谈不上柯里化
    lnim
        6
    lnim  
       2018-09-12 12:08:24 +08:00 via iPhone
    二楼说的很明白了 只要函数有返回值 就都可以这样写啊 而且在函数范式的语言中 函数也能直接当参数使用~
    marcong95
        7
    marcong95  
       2018-09-12 12:09:14 +08:00   1
    数学课本?函数这样用不是理所当然的么?复合函数了解一下?
    kerr92
        8
    kerr92  
       2018-09-12 12:10:43 +08:00 via iPhone   1
    这种一点也不奇怪吧…… JS 里的 c().b().a()都很正常
    mengzhuo
        9
    mengzhuo  
       2018-09-12 12:13:12 +08:00   8
    基础知识啊~

    Go 的话,这是栈(call stack)的作用,不考虑 inline,SSA 这些东西,大概过程是这样的(中文翻译可能不准确)

    语法检查器发现语法 a(b(c())), 校验合格之后,告诉 tokenizer,处理一下。

    tokenizer 把这个拆成( parse )语法树( AST )
    a() --
    |- b()
    |- c()

    然后告诉编译器,处理一下。

    编译器找到语法树叶子节点,反向查找得到执行树 c->b->a,然后依次写机器码

    伪内存地址 0x00001:func c() ... 跳转到 b()

    伪内存地址 0xff002: func b() ... 跳转到 a()

    伪内存地址 0xf1113: func a()

    保存可执行文件退出。
    cuzfinal
        10
    cuzfinal  
       2018-09-12 12:15:11 +08:00   4
    想了解程序的运行?
    :查阅编译原理等相关书籍
    :上论坛发帖询问
    puga2006
        11
    puga2006  
       2018-09-12 12:15:18 +08:00   2
    这个不是最基础的函数编程思想么,我感觉楼主的疑惑倒是怪怪的
    U7Q5tLAex2FI0o0g
        12
    U7Q5tLAex2FI0o0g  
       2018-09-12 12:16:33 +08:00   11
    不觉得楼主像是“写了多年程序”的样子
    arthasgxy
        13
    arthasgxy  
       2018-09-12 12:17:46 +08:00   1
    y=x+1
    z=y+1
    w=z+1

    w=((x+1)+1)+1

    如果这样看起来不感觉奇怪的话。
    你把它写成函数也不会觉得奇怪吧。。。
    imn1
        14
    imn1  
       2018-09-12 12:17:57 +08:00
    区块链……
    tumi9527
        15
    tumi9527  
       2018-09-12 12:18:40 +08:00   1
    php 匿名函数了解一下
    marsgt
        16
    marsgt  
       2018-09-12 12:20:54 +08:00   1
    其实就是数学上把一组复杂函数抽象成单个量的思想,可以去看看《代码之髓》这类的书
    watzds
        17
    watzds  
       2018-09-12 12:21:31 +08:00 via Android   1
    函数式编程只能这样写
    irainsoft
        18
    irainsoft  
       2018-09-12 12:22:11 +08:00   2
    f(g(x))也奇怪吗
    HXM
        19
    HXM  
       2018-09-12 12:22:14 +08:00 via Android   1
    复合函数
    kx5d62Jn1J9MjoXP
        20
    kx5d62Jn1J9MjoXP  
       2018-09-12 12:22:39 +08:00 via Android   1
    斯坦福公开课 CS110 了解一下
    shenjo
        21
    shenjo  
       2018-09-12 12:27:39 +08:00   1
    一等公民了解下?
    shisang
        22
    shisang  
       2018-09-12 12:39:18 +08:00
    fp 了解一下
    wizardoz
        23
    wizardoz  
       2018-09-12 12:41:37 +08:00   1
    求值顺序了解一下
    shisang
        24
    shisang  
       2018-09-12 12:41:56 +08:00   1
    你看到 clojure 不得疯掉,全是括号
    hhsuan
        25
    hhsuan  
       2018-09-12 12:42:36 +08:00 via Android   1
    有什么语言是不能这样写的吗?
    reus
        26
    reus  
       2018-09-12 12:43:02 +08:00   1
    小学生都知道 1 * (2 + 3) 吧。为什么 (2 + 3) 可以做被乘数?一样道理,改成前缀表达式就是 *(1, +(2, 3)),和函数调用就一样了
    rb6221
        27
    rb6221  
       2018-09-12 12:45:01 +08:00   1
    我的年龄是 10+10 岁。
    jmc891205
        28
    jmc891205  
       2018-09-12 12:46:07 +08:00   1
    数学上的 f(g(h(x)))楼主有疑问吗?
    zsdroid
        29
    zsdroid  
       2018-09-12 12:52:18 +08:00   2
    多年写错了吧,可能是多日
    K0
        30
    K0  
       2018-09-12 12:58:10 +08:00 via iPhone   1
    mov eax, dword
    ret
    lzhCoooder
        31
    lzhCoooder  
       2018-09-12 13:04:16 +08:00   1
    c 先压栈执行完弹出,b 再压栈再弹出,a 再压栈再弹出...你再连着用一个线程只有一个调用栈,不影响的
    PythonAnswer
        32
    PythonAnswer  
       2018-09-12 13:05:04 +08:00 via iPhone   1
    各种汇编佬都出来了
    lty494685444
        33
    lty494685444  
       2018-09-12 13:07:20 +08:00   1
    编程水平不知道,不过我感觉楼主你数学应该不太好
    lihongjie0209
        34
    lihongjie0209  
       2018-09-12 13:07:44 +08:00   2
    用过 linux 的管道吗, 一样的

    a(b(c()))

    c() | b | a
    zhzer
        35
    zhzer  
       2018-09-12 13:09:14 +08:00   1
    那你这基础有够逊的
    代码解析成 AST 然后根据后序遍历的顺序,从最底层求值,每一层 function 拿到的都是结果并非过程
    RqPS6rhmP3Nyn3Tm
        36
    RqPS6rhmP3Nyn3Tm  
       2018-09-12 13:10:12 +08:00 via iPhone   1
    汇编,stack pointer
    ksco
        37
    ksco  
       2018-09-12 13:13:05 +08:00   1
    写了多年程序?莫非楼主写的是 PHP ?(狗头保命
    akiakiseofficial
        38
    akiakiseofficial  
       2018-09-12 13:17:31 +08:00 via Android
    编译原理了解一下
    forblackking
        39
    forblackking  
       2018-09-12 13:24:39 +08:00 via Android
    用 FP 来看函数是一等公民可以作为输入输出,内层函数的结果作为参数依次传给外层函数
    misaka19000
        40
    misaka19000  
       2018-09-12 13:26:38 +08:00 via Android
    这和柯里化毛关系没有

    一个字:栈

    话说楼主真不是开黑 PHP 的?
    gesse
        41
    gesse  
       2018-09-12 13:26:57 +08:00
    楼主真的是“写了多年程序”的样子吗?
    jeffersonpig
        42
    jeffersonpig  
       2018-09-12 13:43:12 +08:00
    写了多年程序?
    somebody
        43
    somebody  
       2018-09-12 13:44:07 +08:00 via Android
    看帖子的回复,还是有不少人不懂的
    jeffersonpig
        44
    jeffersonpig  
       2018-09-12 13:45:01 +08:00
    @lihongjie0209 linux 管道对于写了多年程序的人来说可能比函数嵌套调用更难理解吧
    SeanChense
        45
    SeanChense  
       2018-09-12 13:46:11 +08:00
    跟函数式啥关系?

    `exit(main(argc, argv));`

    也是函数式编程么?
    maichael
        46
    maichael  
       2018-09-12 13:59:15 +08:00
    这跟函数式、柯里化有什么关系……又不是传函数进去。

    上面的人是没看清楚还是咋地。
    orange1818
        47
    orange1818  
       2018-09-12 14:03:29 +08:00
    估计是 java 写多了没见过函数式编程
    nervdy
        48
    nervdy  
       2018-09-12 14:07:16 +08:00
    上面的楼全被点了个感谢
    tourist2018
        49
    tourist2018  
       2018-09-12 14:07:55 +08:00
    num := getNum()
    fmt.Println(num)

    ---------------------
    fmt.Println(getNum())


    楼主真的。。。
    shapimai
        50
    shapimai  
       2018-09-12 14:10:26 +08:00
    写了多年程序?
    geelaw
        51
    geelaw  
       2018-09-12 14:10:43 +08:00
    @reus #26 左边是被乘数(这和左边是被除数是一致的)。
    XXneet
        52
    XXneet  
       2018-09-12 14:12:40 +08:00
    抽象数据类型
    bumz
        53
    bumz  
       2018-09-12 14:25:22 +08:00   3
    c() = 2
    b(x) = 3 * x
    a(x) = 4 * x

    a(b(c())) = a(b(2)) = a(6) = 24

    这和数学不是一样的嘛?学名叫 applicative order

    和柯里化、函数式、链式调用有个毛关系

    至于为什么可以这样做?因为等式两边的东西是同一个东西,用哪一个都是一样的。
    merin96
        54
    merin96  
       2018-09-12 14:27:48 +08:00
    xuanbg
        55
    xuanbg  
       2018-09-12 14:31:22 +08:00
    这个就是简单的等价替换而已
    jianleer
        56
    jianleer  
       2018-09-12 14:33:21 +08:00
    因为栈
    GG668v26Fd55CP5W
        57
    GG668v26Fd55CP5W  
       2018-09-12 14:36:44 +08:00 via iPhone
    人的悟性可以差别很大…
    neptuno
        58
    neptuno  
       2018-09-12 14:41:31 +08:00
    指针的指针。。。。
    leeho
        59
    leeho  
       2018-09-12 14:41:59 +08:00
    多年=2 年?
    AV1
        60
    AV1  
       2018-09-12 14:45:24 +08:00
    btoa(encodeURIComponent(JSON.stringify({result:'牛逼牛逼'})))
    >"JTdCJTIycmVzdWx0JTIyJTNBJTIyJUU3JTg5JTlCJUU5JTgwJUJDJUU3JTg5JTlCJUU5JTgwJUJDJTIyJTdE"

    JSON.parse(decodeURIComponent(atob("JTdCJTIycmVzdWx0JTIyJTNBJTIyJUU3JTg5JTlCJUU5JTgwJUJDJUU3JTg5JTlCJUU5JTgwJUJDJTIyJTdE")))
    >{result: "牛逼牛逼"}

    不过这样写很蛋疼,如果有管道操作符就好了
    {result:'牛逼牛逼'} |> JSON.stringify |> encodeURIComponent |> btoa
    >"JTdCJTIycmVzdWx0JTIyJTNBJTIyJUU3JTg5JTlCJUU5JTgwJUJDJUU3JTg5JTlCJUU5JTgwJUJDJTIyJTdE"
    ch940621
        61
    ch940621  
       2018-09-12 14:48:00 +08:00
    写了多年程序厉害了...
    circleee
        62
    circleee  
       2018-09-12 14:52:38 +08:00
    我毕业的时候写过 a = fun()[0]

    哈哈哈哈
    wangjie
        63
    wangjie  
       2018-09-12 15:12:38 +08:00
    @DOLLOR #60 用 babel7 加插件可以用了
    Justin13
        64
    Justin13  
       2018-09-12 15:20:04 +08:00 via Android
    简单的线性流水式调用
    chenxytw
        65
    chenxytw  
       2018-09-12 15:32:35 +08:00   1
    a()()()() 这才是 curry.....
    上面说 柯里化的在想啥
    stevenhawking
        66
    stevenhawking  
       2018-09-12 15:37:09 +08:00
    哦,这有啥,你忘了链式方法?

    ->a()->b()->c()
    persimmon
        67
    persimmon  
       2018-09-12 15:46:28 +08:00
    调用栈不断在加深而已 ......
    SoulGem
        68
    SoulGem  
       2018-09-12 15:48:16 +08:00
    多年程序都写了啥啊……
    Mrlgm
        69
    Mrlgm  
       2018-09-12 16:13:25 +08:00
    就像 jquery 的链式调用一样,返回了个对象呗
    lihongjie0209
        70
    lihongjie029  
       2018-09-12 16:26:33 +08:00   1
    楼上们就知道瞎说, 和函数式有什么关系, 只是在调用的时候参数运算了一下而已, 现在这么多装逼的?

    先反驳一下函数一等公民的.

    函数一等公民是函数可以作为参数和返回值.
    有函数 a, b, c, d

    那么函数 a 可以把 b, c 作为参数, 并返回另一个函数 d: d = a(b, c)

    这才是函数是一等公民


    以楼主的例子, 我完全可以用 JAVA 7 之前的任何版本写出以下代码

    a(b(c()))

    obj.a(obj.b(obj.c()))

    那么是不是说 JAVA 在 7 之前就支持函数式了??
    lihongjie0209
        71
    lihongjie0209  
       2018-09-12 16:27:15 +08:00
    @forblackking 请问在 a(b(c())) 中, 哪里有函数了?
    Malthael
        72
    Malthael  
       2018-09-12 17:04:25 +08:00
    上下文??
    colinlet
        73
    colinlet  
       2018-09-12 17:09:43 +08:00   1
    《数据结构》
    《计算机组成原理》
    《计算机操作系统》
    《计算机网络》
    rockyou12
        74
    rockyou12  
       2018-09-12 17:13:43 +08:00
    lz 一击脱离加发在 php 节点下,莫不是在钓鱼......
    kakalulin
        75
    kakalulin  
       2018-09-12 17:15:03 +08:00
    编译原理了解一下
    GoForce5500
        76
    GoForce5500  
       2018-09-12 18:03:57 +08:00
    推荐 Coursera 上的 Programming Language,第二门课程有一周作业就是拿 Racket 写一个小型解释器。
    CODEWEA
        77
    CODEWEA  
       2018-09-12 18:05:43 +08:00 via iPhone
    求求你 别再黑 php 了 去官网了解下匿名函数
    sampeng
        78
    sampeng  
       2018-09-12 18:08:25 +08:00
    楼上的都介绍计算机系的书籍是什么鬼。。。高中数学里的函数你们吃掉了?
    f(x)和 f(f(x))没见过?
    HowToMakeLove
        79
    HowToMakeLove  
       2018-09-12 18:17:25 +08:00   1
    能分的清,多层嵌套的 for/foreach 这种吗?
    SpiderXiantang
        80
    SpiderXiantang  
       2018-09-12 18:22:27 +08:00
    放入栈 从外到里一个个入栈 然后栈的时候肯定先返回里面的函数吧 瞎说的
    arthas2234
        81
    arthas2234  
       2018-09-12 18:27:35 +08:00
    基础知识不过关啊。。。会去好好学吧
    laqow
        82
    laqow  
       2018-09-12 18:33:16 +08:00 via Android
    看一下 LISP 语言就会觉得不这么写都不正常
    RingoTC
        83
    RingoTC  
       2018-09-12 18:36:13 +08:00
    函数的函数鸭
    bucky
        84
    bucky  
       2018-09-12 18:38:05 +08:00
    这和函数式有什么关系?函数返回值不用变量直接直接传入另一个函数和需要函数式支持?
    RainyH2O
        85
    RainyH2O  
       2018-09-12 18:50:02 +08:00
    第一次看到过程 VS 对象 VS 函数打的这么激烈的
    你们是要给这种调用形式争夺唯一代表权么
    akiakiseofficial
        86
    akiakiseofficial  
       2018-09-12 19:20:43 +08:00 via Android
    t.c:
    int a() {return 1;}
    int b(int i) {return i+1;}
    int c(int i) {return i+1;}
    int main() { c(b(a())); }

    gcc -S t.c -o a.s
    cat a.s:
    ...
    main:
    ...
    movl $0, %eax
    call a
    movl %eax, %edi
    call b
    movl %eax, %edi
    call c
    realpg
        87
    realpg  
    PRO
       2018-09-12 19:24:20 +08:00
    @CODEWEA #77
    ……你怕是对匿名函数有什么误解
    MineDog
        88
    MineDog  
       2018-09-12 19:30:58 +08:00
    47 楼,别黑我 java,这算什么函数式编程,只是方法的返回值作为参数而已,算一个语法糖吧
    lichao
        89
    lichao  
       2018-09-12 19:43:38 +08:00
    c() |> b() |> a()
    luopengfei14
        90
    luopengfei14  
       2018-09-12 19:44:59 +08:00 via iPhone
    @xlui 大佬
    mmdsun
        91
    mmdsun  
       2018-09-12 19:50:09 +08:00 via Android
    楼主问的是函数调用栈帧原理吧
    reus
        92
    reus  
       2018-09-12 21:06:49 +08:00   1
    就一个表达式求值,关函数式、柯里化、调用栈什么事?这里根本就没有出现高阶函数

    f(xxx, ...) 这是函数调用表达式,传入的参数可以是其他表式,也就是可以传入另一个函数调用表达式,同理可以嵌套多层。a(b(c())) 就是嵌套了多层的函数调用表达式。

    水平真低。
    yichinzhu
        93
    yichinzhu  
       2018-09-12 22:12:18 +08:00 via Android
    在 v2 学到了很多黑 PHP 的姿势
    zagreb
        94
    zagreb  
       2018-09-12 22:38:43 +08:00 via iPhone   1
    看了附言 1:
    “不知道基础知识哪里学”,表达式,函数表达式和函数返回值了解一下。函数参数没说一定要变量,表达式就行。
    “ md5(...)”,你想表达的是不是 md5(max(a,b))?
    qiayue
        95
    qiayue  
    PRO
       2018-09-12 22:40:26 +08:00
    a(b(c())) 等价于下面三行
    $cResult = c( );
    $bResult = b( $cResult );
    $aResult = c( $bResult );

    举一个真实例子,get 获取到的数据,先 url decode 之后,再 base64 解码,再 json decode 成数组
    $userUrlEncode = $_GET['user'];
    $userBase64 = urldecode( $userUrlEncode );//传入字符串,返回字符串
    $userJson = base64_decode( $userBase64 );//传入字符串,返回字符串
    $user = json_decode( $userJson );////传入字符串,返回数组
    以上串起来写就是
    $user = json_decode(base64_decode(urldecode( $_GET['user'] )));

    记住,传进去的并不是函数,而是函数返回的结果
    qiayue
        96
    qiayue  
    PRO
       2018-09-12 22:41:14 +08:00
    $aResult = c( $bResult );
    勘误,正确为:
    $aResult = a( $bResult );
    qiayue
        97
    qiayue  
    PRO
       2018-09-12 22:42:46 +08:00
    $user = json_decode( $userJson );////传入字符串,返回数组
    勘误,正确为:
    $userArr = json_decode( $userJson, TRUE );////传入字符串,返回数组
    或者
    $userObj = json_decode( $userJson );////传入字符串,返回对象
    zmj1316
        98
    zmj1316  
       2018-09-12 22:48:03 +08:00
    我刚看到以为是问 C++ 左值右值呢......
    deljuven
        99
    deljuven  
       2018-09-12 22:56:36 +08:00
    1L 的说法是正确的,基本就是计算机语言理论那一套东西,参看 Wikipedia: https://en.wikipedia.org/wiki/Currying
    pinews
        100
    pinews  
    OP
       2018-09-12 23:07:13 +08:00
    @zagreb 感谢,表达式章节的确说了函数也是表达式,只不过在运算符优先级里面提到了 new clone [等运算符,那么按说执行函数其实也是运算符了,和赋值运算符=一样自右至左参与运算。。。
    1  2  
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     885 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 32ms UTC 19:44 PVG 03:44 LAX 12:44 JFK 15:44
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86