这些功能有什么区别

hyd*_*yde 8 f# function currying

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

let f1 a b = a + b

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

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

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

Tom*_*cek 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)
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.您可以以完全相同的方式使用这两种类型的值,但它提示您,当您为其提供单个参数时,第一种类型可能会产生一些效果.


Cra*_*ntz 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
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)

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


pad*_*pad 5

两个功能是相同的.它们可以被认为是语法糖

let f = fun a -> fun b -> a + b
Run Code Online (Sandbox Code Playgroud)

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

在一个侧面说明,对在F#所以功能没有平等f1 5f2 5是不同的值,但它们产生于相同的输入相同的输出.