gpt4 book ai didi

f# - 当嵌套是可选的时,嵌套 f# 函数与不嵌套它们有何不同?

转载 作者:行者123 更新时间:2023-12-01 10:36:10 26 4
gpt4 key购买 nike

当你想返回一个闭包时,我理解嵌套函数的好处。但是当一个函数永远不会在它定义的函数之外使用时,保持它的嵌套是否有代价?

考虑:

let private validate number = 
number > 100

let validateAndPrint (i : int) =
printfn "%i Greater than 100: %s" i ((validate i).ToString())

对比:

let validateAndPrint (i : int) = 
let validate number =
number > 100
printfn "%i Greater than 100: %s" i ((validate i).ToString())

这里的问题通常是当我有一些这样的内部函数并且我只需要根据执行路径调用其中一个时(将这些函数保持私有(private)或嵌套并测试排列通常并不禁止)。

validateAndPrint 也可以重写为对 tdd 更友好,以包含验证函数:

let validateAndPrint validate i = ...

..但是如果validation 的签名包含内部或私有(private)类型,那么就需要考虑将所有内容公开并且您的参数列表会爆炸。

有什么重要区别吗?

最佳答案

Release 模式下,IL 是相同的,并且 validate 的两个版本在这个特定示例中都是内联的。

你不能总是依赖内联,例如如果一个函数“大”,那么编译器可以选择不内联它(这对于方法是正确的,我不是 100% 确定这对于 F# 嵌套函数是正确的。不可能将它们标记为 inline 和强制内联,- 如果此类函数的行为类似于方法或始终在 Release 中内联,则需要查阅 F# 规范)。在 Debug 模式的嵌套情况下,有额外的 FSharpFunc 分配和 callvirt。如果没有嵌套,它只是一个没有分配的静态调用,这是所有可能实现中成本最低的。

所以一般来说,如果嵌套确实是可选的,那么避免它会更安全,因为即使一个函数没有内联,它也总是作为静态方法被调用。但是,只有当您每秒调用此代码数百万次时,它才有意义。

IL_0019 上的非嵌套静态调用:

.method public static 
void validateAndPrint (
int32 i
) cil managed
{
// Method begins at RVA 0x2104
// Code size 51 (0x33)
.maxstack 5
.locals init (
[0] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>,
[1] bool
)

IL_0000: ldstr "%i Greater than 100: %s"
IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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 [mscorlib]System.Tuple`2<int32, string>>::.ctor(string)
IL_000a: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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_000f: stloc.0
IL_0010: nop
IL_0011: ldloc.0
IL_0012: newobj instance void FSSO.Test/validateAndPrint@8::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>)
IL_0017: ldarg.0
IL_0018: ldarg.0
IL_0019: call bool FSSO.Test::validate(int32)
IL_001e: stloc.1
IL_001f: ldloca.s 1
IL_0021: constrained. [mscorlib]System.Boolean
IL_0027: callvirt instance string [mscorlib]System.Object::ToString()
IL_002c: call !!0 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, string>::InvokeFast<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!0, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!1, !!0>>, !0, !1)
IL_0031: pop
IL_0032: ret
} // end of method Test::validateAndPrint

嵌套,IL_0018 上的分配和 IL_0020 上的 callvirt:

.method public static 
void validateAndPrint (
int32 i
) cil managed
{
// Method begins at RVA 0x2050
// Code size 58 (0x3a)
.maxstack 6
.locals init (
[0] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool> validate,
[1] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>,
[2] bool
)

IL_0000: newobj instance void FSSO.Test2/validate@13::.ctor()
IL_0005: stloc.0
IL_0006: ldstr "%i Greater than 100: %s"
IL_000b: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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 [mscorlib]System.Tuple`2<int32, string>>::.ctor(string)
IL_0010: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormatLine<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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_0015: stloc.1
IL_0016: nop
IL_0017: ldloc.1
IL_0018: newobj instance void FSSO.Test2/'validateAndPrint@14-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>)
IL_001d: ldarg.0
IL_001e: ldloc.0
IL_001f: ldarg.0
IL_0020: callvirt instance !1 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, bool>::Invoke(!0)
IL_0025: stloc.2
IL_0026: ldloca.s 2
IL_0028: constrained. [mscorlib]System.Boolean
IL_002e: callvirt instance string [mscorlib]System.Object::ToString()
IL_0033: call !!0 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, string>::InvokeFast<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!0, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!1, !!0>>, !0, !1)
IL_0038: pop
IL_0039: ret
} // end of method Test2::validateAndPrint

Release模式,IL_0020 上的内联比较:

.method public static 
void validateAndPrint (
int32 i
) cil managed
{
// Method begins at RVA 0x2050
// Code size 57 (0x39)
.maxstack 6
.locals init (
[0] class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>,
[1] class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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>,
[2] bool
)

IL_0000: ldstr "%i Greater than 100: %s"
IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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 [mscorlib]System.Tuple`2<int32, string>>::.ctor(string)
IL_000a: stloc.1
IL_000b: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()
IL_0010: ldloc.1
IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatLineToTextWriter<class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, 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: stloc.0
IL_0017: nop
IL_0018: ldloc.0
IL_0019: newobj instance void FSSO.Test2/'validateAndPrint@14-2'::.ctor(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<string, class [FSharp.Core]Microsoft.FSharp.Core.Unit>>)
IL_001e: ldarg.0
IL_001f: ldarg.0
IL_0020: ldc.i4.s 100
IL_0022: cgt
IL_0024: stloc.2
IL_0025: ldloca.s 2
IL_0027: constrained. [mscorlib]System.Boolean
IL_002d: callvirt instance string [mscorlib]System.Object::ToString()
IL_0032: call !!0 class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, string>::InvokeFast<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!0, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!1, !!0>>, !0, !1)
IL_0037: pop
IL_0038: ret
} // end of method Test2::validateAndPrint

关于f# - 当嵌套是可选的时,嵌套 f# 函数与不嵌套它们有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35042627/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com