2011-03-17 21 views
17

FSharp.Core ve PowerPack'deki kaynağa baktığımda, iki veya daha fazla parametreli bir işlevi kabul eden çok sayıda yüksek değerli işlevlerin FSharpFunc.Adapt'u kullandığını görüyorum. Örneğin: FSharpFunc.Adapt üzerineFSharpFunc.Adapt ne zaman kullanılmalı?

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 

belgeler oldukça incedir. Bu, benzer bir imza ile daha yüksek sıralı bir işleve sahip olduğumuz her zaman kullanmamız gereken genel bir en iyi uygulamadır mı? Yalnızca aktarılan işlev birden çok kez çağrıldıysa? Optimizasyon ne kadar? Her yerde Adapt kullanıyor muyuz, yoksa sadece nadiren mi?

Zaman ayırdığınız için teşekkür ederiz.

cevap

13

Bu oldukça ilginç! Herhangi bir resmi bilgim yok (ve bunu herhangi bir yerde belgelenmiş gibi görmedim), ama burada Adapt işlevinin nasıl çalıştığı hakkında bazı düşünceler var.

mapi gibi işlevler, bir işlevin kederli biçimini alır; bu, bağımsız değişken türünün FSharpFunc<int, FSharpFunc<T, R>> gibi bir şeye derlendiği anlamına gelir. Ancak, birçok işlev aslında iki argümanın işlevleri olarak derlenir, bu nedenle gerçek değer genellikle FSharpFunc<int, FSharpFunc<T, R>>'dan gelen FSharpFunc<int, T, R> olur. Eğer InvokeFast fonksiyon kullanılarak Reflektör bakarsak, işlevin derlenmiş olup olmadığını test etmektedir göreceksiniz

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

: Bu işlevi çağırırsanız

(örn f 1 "a") F # derleyicisi böyle bir şey üretir optimize edilmiş versiyon olarak (f :? FSharpFunc<int, T, R>). Eğer evet ise, o zaman doğrudan Invoke(1, "a")'u arar ve eğer değilse o zaman Invoke(1).Invoke("a") iki çağrı yapması gerekir.

Bu onay, argüman olarak iletilen bir işlevi çağırdığınızda her defasında yapılır (muhtemelen daha hızlı bir şekilde kontrol yapmak daha hızlıdır ve daha sonra en iyi duruma getirilmiş olan çağrıyı kullanabilirsiniz).

Adapt işlevinin işlevi, herhangi bir işlevi FSharpFunc<T1, T2, R>'a dönüştürmesidir (işlev en iyileştirilmemişse, bunun için bir sarmalayıcı oluşturur, ancak çoğu zaman geçerli değildir). Uyarlanan işleve yapılan çağrılar daha hızlı olacaktır, çünkü her seferinde dinamik kontrolü yapmaları gerekmemektedir (kontrol, sadece Adapt içerisinde bir kez yapılır).

Özetle, Adapt, 1'den fazla argümanı çok kez alan bir argüman olarak iletilen bir işlevi çağırıyorsanız, performansı artırabilir. Herhangi bir optimizasyonda olduğu gibi, bunu körü körüne kullanmazdım, ancak performansı ayarlarken dikkat edilmesi gereken ilginç bir şey!

(BTW: Çok ilginç bir soru için teşekkürler, derleyicinin bunu yaptığından emin değildim :-))

İlgili konular