What is the difference between these features

Are these functions the same? That is, the first and second syntax is just a convenient shorthand for the last syntax? Or is there any theoretical or practical difference, and if so, what is it?

let f1 ab = a + b

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

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

They seem to be the same to me, for example, f1 5 , f2 5 and f3 5 seem to return the same value. Just checking that I'm not making an invalid assumption here. In other words, I hope for a knowledge-based answer, and not for one statement, β€œYes, I think they are the same.”

+8
function currying f #
source share
3 answers

Your assumption is correct, in this case the functions exactly match.

You can see this by checking the generated IL code (as shown by Craig), and you can also see this by looking at the type output by the F # compiler. In both cases, you will see int -> int -> int . The F # language considers this as a function that takes an int and returns int -> int , but actually compiles as a method with several arguments (for efficiency).

If you write fun immediately after let .. = , then the compiler will turn this into a standard function. However, you can write code that is slightly different if you do some calculations before returning the function:

 let f1 ab = printfn "hi"; a + b let f2 a = printfn "hi"; (fun b -> a + b) 

Now the two functions are very different, because the second prints "hi" when you give it only one argument (and then returns a function that you can call):

 > 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 

You can write the same code with f1 , but the first command will simply create a new function, and the second command will print β€œhello” and add.

In this case, the generated IL code for f2 will be different. This will be a function that returns a function (of type FSharpFunc<int, int> ). The type displayed by F # is also different: type int -> (int -> int) instead of int -> int -> int . You can use the values ​​of these two types in exactly the same way, but this hints that the former may have some effects when you give it one argument.

+8
source share

Here is the IL for 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 

... and for 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 

As you can see, it is almost identical, so yes, they are the same.

+5
source share

Two functions are the same. They could be considered as syntactic sugars for

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

There is a small practical difference. f1 emphasizes that the function returns a value, and f2 returns a closure, which in turn produces a value. Using f2 bit more attractive in creating combinators, for example. parser combinators .

On the side of the note, there is no equality for the functions in F #, so f1 5 and f2 5 are different values, but they give the same outputs on the same inputs.

+5
source share

All Articles