有时F#不会内联函数,即使它被标记为`inline`?

时间:2013-07-28 20:22:50

标签: f# inline

let inline funA x =
    printf "A"
    x > 3

let inline funB myFun x =
    printf "B"
    myFun x

let foo () =
    funB funA 7

IL foo

.method public static 
    bool foo () cil managed 
{
    // Method begins at RVA 0x2278
    // Code size 31 (0x1f)
    .maxstack 4
    .locals init (
        [0] class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>
    )

    IL_0000: nop
    IL_0001: ldstr "B"
    IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
    IL_000b: stloc.0
    IL_000c: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()
    IL_0011: ldloc.0
    IL_0012: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatToTextWriter<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
    IL_0017: pop
    IL_0018: ldc.i4.7
    IL_0019: call bool Foo::myFun@21(int32)  // Here!
    IL_001e: ret
} // end of method Foo::foo

IL myFun@21

    .method assembly static 
        bool myFun@21 (
            int32 x
        ) cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x224c
        // Code size 29 (0x1d)
        .maxstack 4
        .locals init (
            [0] class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>
        )

        IL_0000: ldstr "A"
        IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
        IL_000a: stloc.0
        IL_000b: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()
        IL_0010: ldloc.0
        IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatToTextWriter<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
        IL_0016: pop
        IL_0017: nop
        IL_0018: ldarg.0
        IL_0019: ldc.i4.3
        IL_001a: cgt
        IL_001c: ret
    } // end of method Foo::myFun@21

IL funA

.method public static 
    bool funA (
        int32 x
    ) cil managed 
{
    // Method begins at RVA 0x2218
    // Code size 22 (0x16)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldstr "A"
    IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
    IL_000b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormat<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
    IL_0010: pop
    IL_0011: ldarg.0
    IL_0012: ldc.i4.3
    IL_0013: cgt
    IL_0015: ret
} // end of method Foo::funA

正如您所看到的,myFun@21几乎与funA完全相同,我不明白为什么它存在。为什么函数没有内联?是因为我将一个函数作为参数传递给另一个函数吗?在这种情况下,我认为没有任何难以解决封闭的事情使其无法内联。

是否有任何资源可以让我更多地了解函数何时被标记为inline而无法内联?

1 个答案:

答案 0 :(得分:3)

我相信这个功能是内联的,而不是你想象的方式。 funA只有在有参数的情况下才能内联。由于您没有在使用时向funA提供参数,编译器会将其视为fun x -> funA x并在那里内联funA - 因此创建了一个lambda,就好像你写的那样:

let foo() = 
    printf "B"
    (fun x -> 
        printf "A"
        x > 3) 7