2011-03-17 172 views
17

综观FSharp.Core和PowerPack的来源,我看到了很多的接受两个或多个参数的函数高阶函数使用FSharpFunc.Adapt。例如:什么时候应该使用FSharpFunc.Adapt?

let mapi f (arr: ResizeArray<_>) = 
    let f = FSharpFunc<_,_,_>.Adapt(f) 
    let len = length arr 
    let res = new ResizeArray<_>(len) 
    for i = 0 to len - 1 do 
     res.Add(f.Invoke(i, arr.[i])) 
    res 

关于FSharpFunc.Adapt的文档非常薄。这是一个普遍的最佳实践,我们应该在任何时候使用具有类似签名的高阶函数来使用它。只有当传入的函数被多次调用?它有多少优化?我们是否应该在任何地方使用Adapt,或者很少?

谢谢你的时间。

回答

13

这是相当有趣!我没有任何官方信息(和我没有看到这个文件的任何地方),但这里有对Adapt功能是如何发挥作用的一些想法。

mapi这样的函数采用了函数的curry形式,这意味着参数的类型被编译成类似FSharpFunc<int, FSharpFunc<T, R>>的东西。然而,许多功能实际上是直接编译为两个参数的函数,因此实际值通常会FSharpFunc<int, T, R>FSharpFunc<int, FSharpFunc<T, R>>继承。

如果调用此函数(例如,f 1 "a")F#编译器生成这样的事情:

FSharpFunc<int, string>.InvokeFast<a>(f, 1, "a"); 

如果你看一下InvokeFast功能使用反射,你会看到它测试,如果函数编译作为优化版本(f :? FSharpFunc<int, T, R>)。如果是,那么它直接呼叫Invoke(1, "a"),如果不是,则需要拨打两个电话Invoke(1).Invoke("a")

该检查是在每次调用作为参数传递的函数时(它可能是更快地做检查,然后使用专用电话,因为这是比较常见的)来完成。

什么Adapt函数做的是将其转换为FSharpFunc<T1, T2, R>任何功能(如果该功能尚未进行优化,它创造了它的包装,但是这不是大部分时间的情况下)。经调整的功能的调用会更快,因为他们不需要每次(支票里面Adapt只进行一次)做动态检查。

所以,总结是Adapt可以提高性能,如果你调用一个函数作为一个参数传递多次参数多次。就像任何优化一样,我不会盲目地使用它,但在调整性能时要注意它是一件有趣的事情!

(顺便说一句:谢谢你一个很有趣的问题,我不知道该编译器这个:-))

相关问题