这些功能有什么区别

时间:2012-10-30 12:55:16

标签: function f# currying

这些功能完全相同吗?也就是说,第一和第二语法是最后一种语法的简便方法吗?或者是否存在一些理论上或实际上的差异,如果是,那又是什么?

let f1 a b = a + b

let f2 a = (fun b -> a + b)

let f3 = (fun a -> (fun b -> a + b) )

对我来说,它们似乎相同,f1 5f2 5f3 5似乎返回相同的值。只是检查我在这里没有做出无效的假设。换句话说,我希望以知识为基础的答案,而不是说“是的,我相信它们是相同的”。

3 个答案:

答案 0 :(得分:8)

您的假设是正确的,在这种情况下,功能完全相同。

您可以通过检查生成的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)

现在这两个函数非常不同,因为当你给它一个参数时,第二个函数会打印“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

您可以使用f1编写相同的代码,但第一个命令只会创建一个新函数,第二个命令将打印“hi”并执行添加。

在这种情况下,f2生成的IL代码将不同。它将是返回函数(类型为FSharpFunc<int, int>)的函数。 F#显示的类型也不同 - 它将是int -> (int -> int)而不是int -> int -> int。您可以以完全相同的方式使用这两种类型的值,但它提示您,当您给它一个参数时,第一种可能会产生一些效果。

答案 1 :(得分:5)

这是f1的IL:

.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

...对于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

正如你所看到的,它基本相同,所以是的,它们是相同的。

答案 2 :(得分:5)

两个功能是相同的。

可以将它们视为语法糖
let f = fun a -> fun b -> a + b

实际差异很小。 f1强调函数返回一个值,而f2返回一个闭包,而闭包又产生一个值。使用f2在创建组合器方面更具吸引力,例如parser combinators

另一方面,F#中的函数没有相等性,因此f1 5f2 5是不同的值,但它们在相同的输入上产生相同的输出。