OCaml会将多参数函数转换为currying还是反之? [英] Will OCaml convert multi-argument function to currying or the other way around?

查看:70
本文介绍了OCaml会将多参数函数转换为currying还是反之?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我学习OCaml基本知识时,我被告知OCaml中的每个函数实际上都是只有一个参数的函数.多参数函数实际上是一个带有一个参数并返回一个带有下一个argumetn并返回....的函数.

When I was learning OCaml essentials, I was told that every function in OCaml is actually a function with only one parameter. A multi-argument function is actually a function that takes one argument and returns a function that takes the next argumetn and returns ....

这很烦人,我明白了.

This is currying, I got that.

我的问题是:

案例1

如果我愿意

let plus x y = x + y

在OCaml编译时,OCaml是否会将其更改为let plus = fun x -> fun y -> x + y?

Inside OCaml when it compiles, will OCaml change it to let plus = fun x -> fun y -> x + y?

反之亦然

案例2

如果我这样做

let plus = fun x -> fun y -> x + y

OCaml会将其转换为let plus x y = x + y吗?

OCaml will convert it to let plus x y = x + y?

哪种情况是正确的?在正确的情况下,OCaml编译器的好处或优化是什么?

Which case is true? What's the benifit or optimisation OCaml compiler has done in the correct case?

此外,如果情况2 是正确的,那么考虑OCaml在做些什么呢?我的意思是实际上是相反的方式,对吗?

In addition, if case 2 is true, then what is the point to consider OCaml is doing currying? I mean it actually does the opposite way, right?

此问题实际上与了解Core的`Fn.const` 有关

推荐答案

let plus x y = x + ylet plus = fun x -> fun y -> x + y都将被编译为相同的代码:

Both let plus x y = x + y and let plus = fun x -> fun y -> x + y will be compiled to the same code:

camlPlus__plus:
    leaq    -1(%rax, %rbx), %rax
    ret

是的,恰好是两个汇编程序指令,没有任何序言和结尾.

Yes, exactly two assembler instructions, without any prologues and epilogues.

OCaml编译器执行优化的几个步骤,并且实际上在不同的类别中思考".例如,两个函数都用相同的lambda代码表示:

OCaml compiler performs several steps of optimizations, and actually "thinks" in a different categories. For example, both functions are represented with the same lambda code:

(function x y (+ x y))

我认为,根据上述lambda,您可能会认为OCaml编译器会转换为非咖喱版本.

I think, that according to the lambda above, you may think that OCaml compiler transforms to a non-curried version.

我还要添加一些关于内核的const函数的信息.假设我们有两个const函数在语义上等效的表示形式:

I would also like to add a few words about the core's const function. Suppose we have two semantically equivalent representations of the const function:

let const_xxx c = (); fun _ -> c
let const_yyy c _ = c

以lambda形式表示为:

in a lambda form they will be represented as:

(function c (seq 0a (function param c))) ; const_xxx
(function c param c)                     ; const_yyy

因此,如您所见,const_xxx确实是以咖喱形式编译的.

So, as you can see, const_xxx is indeed compiled in a curried form.

但是最有趣的问题是,为什么值得用这样晦涩的代码来编写它.汇编输出(amd64)中可能有一些线索:

But the most interesting question, is why it is worth to write it in a such obscure code. Maybe there're some clues in assembly output (amd64):

camlPlus__const_xxx_1008:
    subq    $8, %rsp
.L101:
    movq    %rax, %rbx                    ; save c into %rbx (it was in %rax)
.L102:  
    subq    $32, %r15                     ; allocate memory for a closure
    movq    caml_young_limit(%rip), %rax  ; check
    cmpq    (%rax), %r15                  ; that we have memory, if not
    jb      .L103                         ; then free heap and go back
    leaq    8(%r15), %rax                 ; load closure address to %rax
    movq    $3319, -8(%rax)
    movq    camlPlus__fun_1027(%rip), %rdi
    movq    %rdi, (%rax)
    movq    $3, 8(%rax)
    movq    %rbx, 16(%rax)                ; store parameter c in the closure
    addq    $8, %rsp             
    ret                                   ; return the closure
.L103:  call    caml_call_gc@PLT
.L104:  jmp .L102

const_yyy呢?它可以简单地编译为:

What about const_yyy? It is compiled simply as:

camlPlus__const_yyy_1010:
    ret

只需返回参数即可.因此,假设优化的实际点是在const_xxx中,闭包创建是在函数内部编译的并且应该是快速的.另一方面,const_yyy不会以咖喱的方式被调用,因此,如果您在没有所有必需参数的情况下调用它,那么编译器需要在const_yyy处添加创建闭包的代码.部分应用程序(即,每次调用const_xxx x时都要执行const_xxx中的所有操作).

Just return the argument. So, it is assumed that the actual point of optimization, is that in const_xxx the closure creation is compiled inside the function and should be fast. On the other hand, const_yyy doesn't expect to be called in a curried way, so if you will call it without all the needed parameters, then compiler needs to add the code that creates a closure in the point of const_yyy partial application (i.e., to perform all the operations in the const_xxx every time you call const_xxx x).

最后,const优化创建了针对部分应用程序优化的功能.虽然,它伴随着成本.如果使用所有参数调用未优化的const函数,它们的性能将优于优化的函数. (实际上,当我使用两个参数时,我的参数甚至删除了对const_yyy的调用.

To conclude, const optimization creates a function that is optimized for partial application. Although, it comes with cost. A non-optimized const function will outperform the optimized if they are called with all parameters. (Actually my parameter even droped a call to const_yyy when I applied it with two args.

这篇关于OCaml会将多参数函数转换为currying还是反之?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆