Parameters voor statisch opgelost type

Een statisch opgeloste typeparameter is een typeparameter die wordt vervangen door een werkelijk type tijdens het compileren in plaats van tijdens runtime.

Syntaxis

'type-parameter

Tot versie 7.0 van F# moest men de volgende syntaxis gebruiken

^type-parameter

Opmerkingen

In F# zijn er twee verschillende typen parameters. Het eerste type is de standaard algemene typeparameter. Ze zijn gelijk aan algemene typeparameters in andere .NET-talen. Het andere type is statisch omgezet en kan alleen worden gebruikt in inline functies.

Statisch opgeloste typeparameters zijn voornamelijk handig in combinatie met lidbeperkingen. Dit zijn beperkingen waarmee u kunt opgeven dat een typeargument een bepaald lid of een bepaald lid moet hebben om te kunnen worden gebruikt. Er is geen manier om dit type beperking te maken met behulp van een reguliere algemene typeparameter.

De volgende tabel bevat een overzicht van de overeenkomsten en verschillen tussen de twee typen parameters.

Functie Algemeen Statisch opgelost
Oplossingstijd Runtime Compilatietijd
Beperkingen voor leden Kan niet worden gebruikt met lidbeperkingen. Kan worden gebruikt met lidbeperkingen.
Codegeneratie Een type (of methode) met standaard algemene typeparameters resulteert in het genereren van één algemeen type of methode. Er worden meerdere instantiëringen van typen en methoden gegenereerd, één voor elk type dat nodig is.
Gebruiken met typen Kan worden gebruikt voor typen. Kan niet worden gebruikt voor typen.
Gebruiken met inlinefuncties Een inlinefunctie kan niet worden geparameteriseerd met een standaard algemene typeparameter. Als de invoer niet volledig algemeen is, is de F#-compiler gespecialiseerd of krijgt de F#-compiler een fout als er geen opties zijn om te specialiseren. Statische opgeloste typeparameters kunnen niet worden gebruikt voor functies of methoden die niet inline zijn.

Veel F#-kernbibliotheekfuncties, met name operators, hebben statisch opgeloste typeparameters. Deze functies en operators zijn inline en resulteren in efficiënte codegeneratie voor numerieke berekeningen.

Inlinemethoden en -functies die gebruikmaken van operators of andere functies met statisch opgeloste typeparameters kunnen ook zelf statische opgeloste typeparameters gebruiken. Vaak wordt door typedeductie afgeleid dat dergelijke inlinefuncties statisch opgeloste typeparameters hebben. In het volgende voorbeeld ziet u een operatordefinitie die is afgeleid van een statisch opgeloste typeparameter.

let inline (+@) x y = x + x * y
// Call that uses int.
printfn "%d" (1 +@ 1)
// Call that uses float.
printfn "%f" (1.0 +@ 0.5)

Het opgeloste type (+@) is gebaseerd op het gebruik van beide (+) en (*), waardoor typedeductie beperkingen van leden kan afleiden van de statisch opgeloste typeparameters. Het opgeloste type, zoals weergegeven in de F#-interpreter, is als volgt.

'a -> 'c -> 'd
when ('a or 'b) : (static member ( + ) : 'a * 'b -> 'd) and
('a or 'c) : (static member ( * ) : 'a * 'c -> 'b)

De uitvoer is als volgt.

2
1.500000

In het volgende voorbeeld ziet u het gebruik van SRTP's met methoden en statische methoden:

type Record =
    { Number: int }
    member this.Double() = { Number = this.Number * 2 }
    static member Zero() = { Number = 0 }
    
let inline double<'a when 'a:(member Double: unit -> 'a)> (x: 'a) = x.Double()    
let inline zero<'a when 'a:(static member Zero: unit -> 'a)> () = 'a.Zero()

let r: Record = zero ()
let doubleR = double r

Vanaf F# 7.0 kunt u deze gebruiken 'a.Zero() in plaats van de beperking te herhalen, zoals in het onderstaande voorbeeld.

Vanaf F# 4.1 kunt u ook concrete typenamen opgeven in statische typeparameterhandtekeningen. In eerdere versies van de taal werd de typenaam afgeleid door de compiler, maar kon niet worden opgegeven in de handtekening. Vanaf F# 4.1 kunt u ook concrete typenamen opgeven in statische opgeloste typeparameterhandtekeningen. Hier volgt een voorbeeld (niet dat in dit voorbeeld ^ nog steeds moet worden gebruikt omdat de vereenvoudiging voor gebruik ' niet wordt ondersteund):

let inline konst x _ = x

type CFunctor() =
    static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a
    static member inline fmap (f: ^a -> ^b, a: ^a option) =
        match a with
        | None -> None
        | Some x -> Some (f x)

    // default implementation of replace
    static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) =
        ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f))

    // call overridden replace if present
    static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) =
        (^b : (static member replace: ^a * ^b -> ^c) (a, f))

let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) =
        ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f))

// Note the concrete type 'CFunctor' specified in the signature
let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or  ^b): (static member replace: ^a *  ^b ->  ^a0) =
    replace_instance<CFunctor, _, _, _> (a, f)

Zie ook