pinews
V2EX  ›  PHP

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

  •  
  •   pinews · Sep 12, 2018 · 18544 views
    This topic created in 2973 days ago, the information mentioned may be changed or developed.
    就是 a(b(c()))这样,虽然经常这样用,总觉得怪怪的,不知道在哪里是否有专门的说明?
    Supplement 1  ·  Sep 12, 2018

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

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

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

    Supplement 2  ·  Sep 13, 2018
    感谢博学多识的 FrankHB,他给出了 php 的设计说明书:
    https://github.com/php/php-langspec/blob/master/spec/10-expressions.md#function-call-operator

    噫吁嚱!危乎高哉!
    148 replies  •  2018-09-14 10:23:21 +08:00
    1  2  
    ❮ ❯
    est
    est
    Sep 12, 2018❤️2
    1
    咖喱化(科里化)?
    javaWeber
    javaWeber
    Sep 12, 2018❤️4
    2
    从内向外,函数返回的结果,作为参数使用呗。。
    deston
    deston
    Sep 12, 2018❤️3
    3
    2 楼上说的很清楚了,我来看看楼下怎么说
    zn
    zn
    Sep 12, 2018 via iPhone❤️1
    4
    函数调用得到的就是一个值,跟一个普通的 1 在本质上没什么区别,都是堆栈上的一个条目而已。
    Fairy1128
    Fairy1128
    Sep 12, 2018❤️2
    5
    函数的结果作为参数传递给另一个函数 很正常啊 又不是 callback 更谈不上柯里化
    lnim
    lnim
    Sep 12, 2018 via iPhone
    6
    二楼说的很明白了 只要函数有返回值 就都可以这样写啊 而且在函数范式的语言中 函数也能直接当参数使用~
    marcong95
    marcong95
    Sep 12, 2018❤️1
    7
    数学课本?函数这样用不是理所当然的么?复合函数了解一下?
    kerr92
    kerr92
    Sep 12, 2018 via iPhone❤️1
    8
    这种一点也不奇怪吧…… JS 里的 c().b().a()都很正常
    mengzhuo
    mengzhuo
    Sep 12, 2018❤️8
    9
    基础知识啊~

    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
    cuzfinal
    Sep 12, 2018❤️4
    10
    想了解程序的运行?
    ❌:查阅编译原理等相关书籍
    ⭕️:上论坛发帖询问
    puga2006
    puga2006
    Sep 12, 2018❤️2
    11
    这个不是最基础的函数编程思想么,我感觉楼主的疑惑倒是怪怪的🤔
    U7Q5tLAex2FI0o0g
    U7Q5tLAex2FI0o0g
    Sep 12, 2018❤️11
    12
    不觉得楼主像是“写了多年程序”的样子
    arthasgxy
    arthasgxy
    Sep 12, 2018❤️1
    13
    y=x+1
    z=y+1
    w=z+1

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

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

    a(b(c()))

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

    一个字:栈

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

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

    也是函数式编程么?
    maichael
    maichael
    Sep 12, 2018
    46
    这跟函数式、柯里化有什么关系……又不是传函数进去。

    上面的人是没看清楚还是咋地。
    orange1818
    orange1818
    Sep 12, 2018
    47
    估计是 java 写多了没见过函数式编程
    nervdy
    nervdy
    Sep 12, 2018
    48
    上面的楼全被点了个感谢
    tourist2018
    tourist2018
    Sep 12, 2018
    49
    num := getNum()
    fmt.Println(num)

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


    楼主真的。。。
    shapimai
    shapimai
    Sep 12, 2018
    50
    写了多年程序?
    geelaw
    geelaw
    Sep 12, 2018
    51
    @reus #26 左边是被乘数(这和左边是被除数是一致的)。
    XXneet
    XXneet
    Sep 12, 2018
    52
    抽象数据类型
    bumz
    bumz
    Sep 12, 2018❤️3
    53
    c() = 2
    b(x) = 3 * x
    a(x) = 4 * x

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

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

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

    至于为什么可以这样做?因为等式两边的东西是同一个东西,用哪一个都是一样的。
    xuanbg
    xuanbg
    Sep 12, 2018
    55
    这个就是简单的等价替换而已
    xinghelee
    xinghelee
    Sep 12, 2018
    56
    因为栈
    GG668v26Fd55CP5W
    GG668v26Fd55CP5W
    Sep 12, 2018 via iPhone
    57
    人的悟性可以差别很大…
    neptuno
    neptuno
    Sep 12, 2018
    58
    指针的指针。。。。
    leeho
    leeho
    Sep 12, 2018
    59
    多年=2 年?
    AV1
    AV1
    Sep 12, 2018
    60
    btoa(encodeURIComponent(JSON.stringify({result:'牛逼牛逼'})))
    >"JTdCJTIycmVzdWx0JTIyJTNBJTIyJUU3JTg5JTlCJUU5JTgwJUJDJUU3JTg5JTlCJUU5JTgwJUJDJTIyJTdE"

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

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

    哈哈哈哈
    wangjie
    wangjie
    Sep 12, 2018
    63
    @DOLLOR #60 用 babel7 加插件可以用了
    Justin13
    Justin13
    Sep 12, 2018 via Android
    64
    简单的线性流水式调用
    chenxytw
    chenxytw
    Sep 12, 2018❤️1
    65
    a()()()() 这才是 curry.....
    上面说 柯里化的在想啥
    stevenhawking
    stevenhawking
    Sep 12, 2018
    66
    哦,这有啥,你忘了链式方法?

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

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

    函数一等公民是函数可以作为参数和返回值.
    有函数 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
    lihongjie0209
    Sep 12, 2018
    71
    @forblackking 请问在 a(b(c())) 中, 哪里有函数了?
    Malthael
    Malthael
    Sep 12, 2018
    72
    上下文??
    colinlet
    colinlet
    Sep 12, 2018❤️1
    73
    《数据结构》
    《计算机组成原理》
    《计算机操作系统》
    《计算机网络》
    rockyou12
    rockyou12
    Sep 12, 2018
    74
    lz 一击脱离加发在 php 节点下,莫不是在钓鱼......
    kakalulin
    kakalulin
    Sep 12, 2018
    75
    编译原理了解一下
    GoForce5500
    GoForce5500
    Sep 12, 2018
    76
    推荐 Coursera 上的 Programming Language,第二门课程有一周作业就是拿 Racket 写一个小型解释器。
    CODEWEA
    CODEWEA
    Sep 12, 2018 via iPhone
    77
    求求你 别再黑 php 了 去官网了解下匿名函数
    sampeng
    sampeng
    Sep 12, 2018
    78
    楼上的都介绍计算机系的书籍是什么鬼。。。高中数学里的函数你们吃掉了?
    f(x)和 f(f(x))没见过?
    HowToMakeLove
    HowToMakeLove
    Sep 12, 2018❤️1
    79
    能分的清,多层嵌套的 for/foreach 这种吗?
    SpiderXiantang
    SpiderXiantang
    Sep 12, 2018
    80
    放入栈 从外到里一个个入栈 然后栈的时候肯定先返回里面的函数吧 瞎说的
    arthas2234
    arthas2234
    Sep 12, 2018
    81
    基础知识不过关啊。。。会去好好学吧
    laqow
    laqow
    Sep 12, 2018 via Android
    82
    看一下 LISP 语言就会觉得不这么写都不正常
    RingoTC
    RingoTC
    Sep 12, 2018
    83
    函数的函数鸭
    bucky
    bucky
    Sep 12, 2018
    84
    这和函数式有什么关系?函数返回值不用变量直接直接传入另一个函数和需要函数式支持?
    RainyH2O
    RainyH2O
    Sep 12, 2018
    85
    第一次看到过程 VS 对象 VS 函数打的这么激烈的
    你们是要给这种调用形式争夺唯一代表权么
    akiakiseofficial
    akiakiseofficial
    Sep 12, 2018 via Android
    86
    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
    realpg
    Sep 12, 2018
    87
    @CODEWEA #77
    ……你怕是对匿名函数有什么误解
    MineDog
    MineDog
    Sep 12, 2018
    88
    47 楼,别黑我 java,这算什么函数式编程,只是方法的返回值作为参数而已,算一个语法糖吧
    lichao
    lichao
    Sep 12, 2018
    89
    c() |> b() |> a()
    luopengfei14
    luopengfei14
    Sep 12, 2018 via iPhone
    90
    @xlui 大佬
    mmdsun
    mmdsun
    Sep 12, 2018 via Android
    91
    楼主问的是函数调用栈帧原理吧
    reus
    reus
    Sep 12, 2018❤️1
    92
    就一个表达式求值,关函数式、柯里化、调用栈什么事?这里根本就没有出现高阶函数

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

    水平真低。
    yichinzhu
    yichinzhu
    Sep 12, 2018 via Android
    93
    在 v2 学到了很多黑 PHP 的姿势😑
    zagreb
    zagreb
    Sep 12, 2018 via iPhone❤️1
    94
    看了附言 1:
    “不知道基础知识哪里学”,表达式,函数表达式和函数返回值了解一下。函数参数没说一定要变量,表达式就行。
    “ md5(...)”,你想表达的是不是 md5(max(a,b))?
    qiayue
    qiayue
    Sep 12, 2018
    95
    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
    qiayue
    Sep 12, 2018
    96
    $aResult = c( $bResult );
    勘误,正确为:
    $aResult = a( $bResult );
    qiayue
    qiayue
    Sep 12, 2018
    97
    $user = json_decode( $userJson );////传入字符串,返回数组
    勘误,正确为:
    $userArr = json_decode( $userJson, TRUE );////传入字符串,返回数组
    或者
    $userObj = json_decode( $userJson );////传入字符串,返回对象
    zmj1316
    zmj1316
    Sep 12, 2018
    98
    我刚看到以为是问 C++ 左值右值呢......
    deljuven
    deljuven
    Sep 12, 2018
    99
    1L 的说法是正确的,基本就是计算机语言理论那一套东西,参看 Wikipedia: https://en.wikipedia.org/wiki/Currying
    pinews
    pinews
    OP
    Sep 12, 2018
    100
    @zagreb 感谢,表达式章节的确说了函数也是表达式,只不过在运算符优先级里面提到了 new clone [等运算符,那么按说执行函数其实也是运算符了,和赋值运算符=一样自右至左参与运算。。。
    1  2  
    ❮ ❯
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   5804 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 211ms · UTC 02:26 · PVG 10:26 · LAX 18:26 · JFK 21:26
    ♥ Do have faith in what you're doing.