Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't F# Compile Currying into Separate Functions?

Tags:

f#

c#-to-f#

So I'm trying to learn F# and as I learn new things I like to look at the IL to see what's happening under the covers. I recently read about Currying, an obvious fundamental of the language.

According to F# for fun and Profit when you create the below function:

let addItems x y = x + y

What is really happening is there are two single argument functions being created.

let addItems x =
    let subFunction y = 
          x + y
    subFunction

and when you invoke the function with addItems 5 6 the order of operations are as follows

  1. addItems is called with argument 5

  2. addItems returns subFunction

  3. subFunction is called with argument 6
  4. subFunction has argument 5 in scope so it adds and returns the sum of 5 and 6

All of this sounds fine on the surface. However, when you look at the IL for this it tells a different story.

.method public static int32  testCurry(int32 x,
                                       int32 y) 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  8
  IL_0000:  nop
  IL_0001:  ldarg.0
  IL_0002:  ldarg.1
  IL_0003:  add
  IL_0004:  ret
} // end of method Sandbox::testCurry

We can clearly see in the IL that a single static function that takes two arguments and returns an Int32 is created.

So my question is, why the discrepancy? This isn't the first time I've seen IL that doesn't jive with the documentation either...

like image 531
Anthony Russell Avatar asked Feb 15 '17 18:02

Anthony Russell


1 Answers

So my question is, why the discrepancy?

The actual compiled IL doesn't need to, and really shouldn't, matter in terms of the behavioral contract. By compiling to a single function, a call gets significantly better optimization at the JIT/runtime level.

The "what is really happening here..." isn't necessarily what is actually happening, it's more "how this should be reasoned about when writing and using F# code is...". The underlying implementation should be free to change as needed, in order to make the best use of the runtime environment.

like image 130
Reed Copsey Avatar answered Nov 01 '22 22:11

Reed Copsey