你的假设是正确的,在这种情况下,函数是完全相同的.
您可以通过检查生成的IL代码(如Craig所示)来查看,您还可以通过查看F#编译器推断的类型来查看.在这两种情况下,你都会看到int -> int -> int.F#语言将其视为一个获取int和返回的函数,int -> int但实际上它被编译为具有多个参数的方法(为了提高效率).
如果您之后fun立即编写,let .. =则编译器将其转换为标准函数.但是,如果在返回函数之前进行一些计算,则可以编写有点不同的代码:
let f1 a b = printfn "hi"; a + b
let f2 a = printfn "hi"; (fun b -> a + b)
Run Code Online (Sandbox Code Playgroud)
现在这两个函数是非常不同的,因为当你给它一个参数时,第二个函数打印"hi"(然后它返回一个你可以调用的函数):
> let f = f2 1;;
hi // The body is called, prints
val f : (int -> int) // and returns function
> f 2;; // This runs the body of 'fun'
val it : int = 3 // which performs the additiion
Run Code Online (Sandbox Code Playgroud)
您可以使用相同的代码编写f1,但第一个命令将只创建一个新函数,第二个命令将打印"hi"并执行添加.
在这种情况下,生成的IL代码f2将是不同的.它将是一个返回函数(类型FSharpFunc<int, int>)的函数.F#显示的类型也不同 - 它将int -> (int -> int)代替int -> int -> int.您可以以完全相同的方式使用这两种类型的值,但它提示您,当您为其提供单个参数时,第一种类型可能会产生一些效果.
这是IL f1:
.method public static int32 f1(int32 a,
int32 b) 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 4
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: add
IL_0004: ret
} // end of method Program::f1
Run Code Online (Sandbox Code Playgroud)
......对于f2:
.method public static int32 f2(int32 a,
int32 b) 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 4
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: add
IL_0004: ret
} // end of method Program::f2
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,它基本上是相同的,所以是的,它们是相同的.
两个功能是相同的.它们可以被认为是语法糖
let f = fun a -> fun b -> a + b
Run Code Online (Sandbox Code Playgroud)
有一点实际差异.f1强调函数返回一个值,同时f2返回一个闭包,而闭包又产生一个值.f2在创建组合器(例如,解析器组合器)中使用更有吸引力.
在一个侧面说明,对在F#所以功能没有平等f1 5和f2 5是不同的值,但它们产生于相同的输入相同的输出.