8

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

let f1 a b = a + b

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

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

例如,它们对我来说似乎相同f1 5f2 5并且f3 5似乎返回相同的值。只是检查我没有在这里做出无效的假设。换句话说,我希望得到一个基于知识的答案,而不是说“是的,我相信它们是一样的”。

4

3 回答 3

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”并进行添加。

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

于 2012-10-30T13:05:46.327 回答
5

这是 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

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

如您所见,它本质上是相同的,所以是的,它们是相同的。

于 2012-10-30T13:05:37.883 回答
5

两个功能是一样的。它们可以被认为是语法糖

let f = fun a -> fun b -> a + b

实际差别不大。f1强调函数返回一个值,同时f2返回一个闭包,而闭包又产生一个值。使用在创建组合器(例如解析器组合f2器)时更具吸引力。

附带说明一下,F# 中的函数不相等,因此f1 5它们f2 5是不同的值,但它们在相同的输入上产生相同的输出。

于 2012-10-30T13:09:52.747 回答