为什么不将F#编译成单独的函数?

时间:2017-02-15 18:25:25

标签: f# c#-to-f#

所以我试图学习F#,当我学习新东西时,我喜欢看IL,看看幕后发生了什么。我最近读到了Currying,这是该语言的一个明显基础。

根据F# for fun and Profit创建以下功能时:

let addItems x y = x + y

真正发生的是创建了两个单个参数函数。

let addItems x =
    let subFunction y = 
          x + y
    subFunction

当您使用addItems 5 6调用该函数时,操作顺序如下

  1. 使用参数5

  2. 调用addItems
  3. addItems返回subFunction

  4. 使用参数6
  5. 调用subFunction
  6. subFunction在范围内有参数5,因此它添加并返回5和6的总和
  7. 所有这些听起来都很好。但是,当你看到IL时,它会讲述一个不同的故事。

    .method public static int32  testCurry(int32 x,
                                           int32 y) cil managed
    {
      .custom instance void [FSharp.Core]Microsoft.FSharp.Core.CompilationArgumentCountsAttribute::.ctor(int32[]) = ( 01 00 02 00 00 00 01 00 00 00 01 00 00 00 00 00 ) 
      // Code size       5 (0x5)
      .maxstack  8
      IL_0000:  nop
      IL_0001:  ldarg.0
      IL_0002:  ldarg.1
      IL_0003:  add
      IL_0004:  ret
    } // end of method Sandbox::testCurry
    

    我们可以在IL中清楚地看到,创建了一个带有两个参数并返回Int32的静态函数。

    所以我的问题是,为什么会出现这种差异?这不是我第一次看到IL没有与文档相符......

1 个答案:

答案 0 :(得分:18)

  

所以我的问题是,为什么会出现这种差异?

实际编译的IL不需要,也不应该在行为合同方面很重要。通过编译为单个函数,调用可以在JIT /运行时级别获得明显更好的优化。

“这里真正发生的事情......”并不一定是实际发生的事情,更多的是“在编写和使用F#代码时应该如何理解......”。底层实现应该可以根据需要随意更改,以便充分利用运行时环境。