所以我试图学习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调用该函数时,操作顺序如下
使用参数5
addItems返回subFunction
所有这些听起来都很好。但是,当你看到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没有与文档相符......
答案 0 :(得分:18)
所以我的问题是,为什么会出现这种差异?
实际编译的IL不需要,也不应该在行为合同方面很重要。通过编译为单个函数,调用可以在JIT /运行时级别获得明显更好的优化。
“这里真正发生的事情......”并不一定是实际发生的事情,更多的是“在编写和使用F#代码时应该如何理解......”。底层实现应该可以根据需要随意更改,以便充分利用运行时环境。