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

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

  •  
  •   pinews · 2018-09-12 11:56:54 +08:00 · 15752 次点击
    这是一个创建于 2289 天前的主题,其中的信息可能已经有所发展或是发生改变。
    就是 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
    这个不是最基础的函数编程思想么,我感觉楼主的疑惑倒是怪怪的🤔
    littleylv
        12
    littleylv  
       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)),和函数调用就一样了
    janus77
        27
    janus77  
       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 ?(狗头保命
    xlui
        38
    xlui  
       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
    因为栈
    falcon05
        57
    falcon05  
       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 年?
    DOLLOR
        60
    DOLLOR  
       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
    lihongjie0209  
       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 函数打的这么激烈的
    你们是要给这种调用形式争夺唯一代表权么
    xlui
        86
    xlui  
       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  
       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  
       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  
       2018-09-12 22:41:14 +08:00
    $aResult = c( $bResult );
    勘误,正确为:
    $aResult = a( $bResult );
    qiayue
        97
    qiayue  
       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   ·   实用小工具   ·   5659 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 03:34 · PVG 11:34 · LAX 19:34 · JFK 22:34
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.