Beágyazott függvények

A beágyazott függvények olyan függvények, amelyek közvetlenül a hívókódba integrálódnak.

Beágyazott függvények használata

Statikus típusparaméterek használatakor a típusparaméterek által paraméterezett függvényeknek beágyazottnak kell lenniük. Ez garantálja, hogy a fordító képes feloldani ezeket a típusparamétereket. Általános típusú paraméterek használata esetén nincs ilyen korlátozás.

A tagkorlátozások használatának engedélyezésén kívül a beágyazott függvények hasznosak lehetnek a kód optimalizálásában. A beágyazott függvények túlhasználata azonban azt eredményezheti, hogy a kód kevésbé lesz ellenálló a fordítóoptimalizálások változásaival és a kódtárfüggvények implementálásával szemben. Ezért kerülnie kell a beágyazott függvények használatát az optimalizáláshoz, kivéve, ha minden más optimalizálási technikát kipróbált. A függvények vagy metódusok beágyazott létrehozása néha javíthatja a teljesítményt, de ez nem mindig így van. Ezért teljesítménymérésekkel is ellenőriznie kell, hogy egy adott függvény beágyazott létrehozása valóban pozitív hatással van-e.

A inline módosító a felső szinten, a modul szintjén vagy az osztály metódusszintjén használható függvényekre.

Az alábbi példakód egy beágyazott függvényt mutat be a legfelső szinten, egy beágyazott példánymetódust és egy beágyazott statikus metódust.

let inline increment x = x + 1
type WrapInt32() =
    member inline this.incrementByOne(x) = x + 1
    static member inline Increment(x) = x + 1

Beágyazott függvények és típuskövetkeztetés

A jelenlét hatással van a inline típusbeli következtetésre. Ennek az az oka, hogy a beágyazott függvények statikusan feloldott típusparaméterekkel rendelkezhetnek, míg a nem beágyazott függvények nem. Az alábbi példakód egy olyan esetet mutat be, ahol inline hasznos lehet, mert statikusan feloldott típusparaméterrel rendelkező függvényt, a float konverziós operátort használ.

let inline printAsFloatingPoint number =
    printfn "%f" (float number)

A módosító nélkül a inline típuskövetkeztetés kényszeríti a függvényt egy adott típusra, ebben az esetben int. inline A módosítóval azonban a függvény egy statikusan feloldott típusparaméterre is következtet. inline A módosítónál a típus a következőre lesz következtetve:

^a -> unit when ^a : (static member op_Explicit : ^a -> float)

Ez azt jelenti, hogy a függvény minden olyan típust elfogad, amely támogatja a lebegőpontosra konvertálást.

InlineIfLambda

Az F#-fordító tartalmaz egy optimalizálót, amely kódrészletezést végez. Az InlineIfLambda attribútum lehetővé teszi, hogy a kód opcionálisan jelezze, hogy ha egy argumentumot lambda függvénynek határoznak meg, akkor az argumentumnak mindig beágyazottnak kell lennie a hívási helyeken. További információ: F# RFC FS-1098.

Vegyük például a következő iterateTwice függvényt egy tömb bejárásához:

let inline iterateTwice ([<InlineIfLambda>] action) (array: 'T[]) =
    for i = 0 to array.Length-1 do
        action array[i]
    for i = 0 to array.Length-1 do
        action array[i]

Ha a hívás helye a következő:

let arr = [| 1.. 100 |]
let mutable sum = 0
arr  |> iterateTwice (fun x ->
    sum <- sum + x)

Ezután a kód alining és más optimalizálások után a következő lesz:

let arr = [| 1..100 |]
let mutable sum = 0
for i = 0 to arr.Length - 1 do
    sum <- sum + arr[i] 
for i = 0 to arr.Length - 1 do
    sum <- sum + arr[i] 

Ez az optimalizálás a lambda kifejezés méretétől függetlenül érvényesül. Ez a funkció a ciklusok regisztrációjának feloldására és a hasonló átalakítások megbízhatóbb megvalósítására is használható.

Az opt-in figyelmeztetés (/warnon:3517 vagy tulajdonság <WarnOn>3517</WarnOn>) bekapcsolható, hogy jelezze a kód azon pontjait, ahol InlineIfLambda az argumentumok nem kötődnek a lambda kifejezésekhez a hívási helyeken. Normál helyzetekben ezt a figyelmeztetést nem szabad engedélyezni. Bizonyos típusú nagy teljesítményű programozás esetén azonban hasznos lehet biztosítani, hogy az összes kód beágyazott és összesimított legyen.

A lekért visszahívások optimalizálása

Az ismétlődő aritás-alkalmazkodás elkerülése érdekében, ha a visszahívások nem ágyazhatók be, az F# 11 támogatja OptimizeClosureIfNotInlined a következő mellett InlineIfLambda:

let inline foldItems
    ([<InlineIfLambda; OptimizeClosureIfNotInlined>] folder)
    state
    (items: 'T[]) =
    let mutable total = state
    for item in items do
        total <- folder total item
    total

A függvénynek beágyazottnak kell lennie, mindkét attribútumnak jelen kell lennie, a visszahívást pedig két-öt argumentummal kell lekérni. Egy ismert lambda be tud ágyazni; egy átlátszatlan visszahívás egyszer módosítható. Ehhez az FSharp.Core 11 és a fordító támogatása szükséges, de nem garantálja a nulla foglalást.

Beágyazott függvények hibakeresése

A beágyazott súgókba való lépéshez fordítás optimalizálás nélkül, és a hibakeresési információk megőrzése nélkül. Az F# 11 a normál hívásokat részesíti előnyben ezekben a buildekben:

let inline addFee (fee: decimal) (amount: decimal) =
    let total = amount + fee
    total

let invoiceTotal = addFee 2m 40m
printfn "%M" invoiceTotal
// 42

A mintaprojektben állítson be töréspontot let total, lépjen be addFee, és vizsgálja meg az argumentumait.

Az optimalizált buildek alapértelmezés szerint továbbra is beágyazottak. Egyes szerkezeteknek, beleértve az újra felhasználható kódot és a statikus bővítést igénylő műveleteket, optimalizálás nélkül is beágyazottnak kell lenniük. A régebbi viselkedés igénylésére használható --always-inline .

Beágyazott bővítménykorlátozások a tárakban

Az F# 11.2 nyilvános bővítménytagokat használhat az SRTP-követelmények teljesítéséhez. A nyelvi beállításokra, hatókörre és kódtárra vonatkozó SRTP-korlátozásokról a bővítménytagok című témakörben olvashat.

Lásd még