2011-03-17 207 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可以提高性能,如果你調用一個函數作爲一個參數傳遞多次參數多次。就像任何優化一樣,我不會盲目地使用它,但在調整性能時要注意它是一件有趣的事情!

(順便說一句:謝謝你一個很有趣的問題,我不知道該編譯器這個:-))

相關問題