Poznámka:
Přístup k této stránce vyžaduje autorizaci. Můžete se zkusit přihlásit nebo změnit adresáře.
Přístup k této stránce vyžaduje autorizaci. Můžete zkusit změnit adresáře.
Vložená funkce se staticky vyřešenými parametry typu může vyžadovat člena s konkrétním názvem a podpisem. F# 11.2 umožňuje, aby člen rozšíření v oboru splňoval tento požadavek, i když typ pochází z jiného sestavení.
Pomocí této funkce oddělte obecný algoritmus od adaptérů pro konkrétní typy. Tyto typy nemusíte zabalit ani do nich přidat nominální rozhraní.
Note
V .NET 11.0.100 SDK povolte<LangVersion>preview</LangVersion>, kde kompilátor překládá rozšíření. Viz nastavení jazyka F# 11.2 pro plánovanou skupinou funkcí. Příklady cest a mapování používají knihovnu F# 11.0 a uživatele verze Preview; viz Kompilace knihoven a příjemců.
Přizpůsobení vlastnosti pro sdílený algoritmus
Následující kód aplikace měří cesty reprezentované dvěma existujícími typy rozhraní. Obě cesty mají délku 8:
open System.Numerics
open Structural.Adapters
open Structural.Algorithms
let complexRoute =
[ Complex(0.0, 0.0); Complex(3.0, 4.0); Complex(6.0, 4.0) ]
let vectorRoute =
[ Vector2(0.0f, 0.0f); Vector2(3.0f, 4.0f); Vector2(6.0f, 4.0f) ]
printn (pathLength complexRoute) // 8
printn (pathLength vectorRoute) // 8
Zdroj knihovny definuje Structural.Adapters a Structural.Algorithms. Adaptéry zpřístupňují stejnou vlastnost souřadnic u typů s různými nativními rozhraními API:
type System.Numerics.Complex with
member point.Coordinates = point.Real, point.Imaginary
type System.Numerics.Vector2 with
member point.Coordinates = float point.X, float point.Y
Algoritmus žádá o Coordinates vlastnost vracející dvojici hodnot s plovoucí desetinou čárkou:
let inline coordinates (point: ^Point) : float * float =
(^Point : (member Coordinates: float * float) point)
let inline pathLength (points: ^Point list) =
points
|> List.pairwise
|> List.sumBy (fun (a, b) ->
let ax, ay = coordinates a
let bx, by = coordinates b
let dx, dy = bx - ax, by - ay
sqrt (dx * dx + dy * dy))
V každém konkrétním volání kompilátor vybere člena Coordinates označovaného jako určující omezení. Vložený algoritmus přijímá vnitřní nebo rozšiřující vlastnost; prázdné a jednobodové cesty mají nulovou délku.
Sdílení operace mezi typy kolekcí
Omezení rozšíření také podporují statické členy. Modul knihovny Structural.Adapters definuje adaptéry pomocí existujících List.map a Option.map funkcí:
type List<'T> with
static member Map(source: 'T list, mapping: 'T -> 'U) : 'U list =
List.map mapping source
type Option<'T> with
static member Map(source: 'T option, mapping: 'T -> 'U) : 'U option =
Option.map mapping source
V modulu knihovny Structural.Algorithms požádejte Map člena o úplný typ vstupu:
let inline map (mapping: 'T -> 'U) (source: ^Input) : ^Output =
(^Input :
(static member Map: ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
Aplikace pak může sdílet transformaci, změnit typ elementu a vytvořit mapování přes vnořenou kolekci:
let inline cleanNames values =
map (fun (name: string) -> name.Trim().ToUpperInvariant()) values
let batch: string list = cleanNames [ " Ada "; " grace " ]
let optional: string option = cleanNames (Some " linus ")
let missing: string option = cleanNames (None: string option)
let lengths: int list = map String.length batch
let nested: int option list = map (map String.length) [ Some "abc"; None ]
printfn "%A; %A; %A" batch optional missing
printfn "%A; %A" lengths nested
// ["ADA"; "GRACE"]; Some "LINUS"; None
// [3; 5]; [Some 3; None]
Kompilátor kontroluje názvy a typy členů, nikoli rozhraní ani mapování zákonů. Není to polymorfismus vyššího druhu: žádný parametr představuje konstruktor kontejneru, například F<_>.
Rozšíření operátorů
Operátory můžou používat stejný mechanismus. Například definujte operátor mapování pro seznamy a možnosti:
type List<'T> with
static member (|>>) (source: 'T list, mapping: 'T -> 'U) =
List.map mapping source
type Option<'T> with
static member (|>>) (source: 'T option, mapping: 'T -> 'U) =
Option.map mapping source
let inline (|>>) (source: ^Input) (mapping: 'T -> 'U) : ^Output =
(^Input :
(static member (|>>): ^Input * ('T -> 'U) -> ^Output)
(source, mapping))
Uživatel se otevře StructuralOperators a použije operátor:
open StructuralOperators
let incremented: int list = [1; 2; 3] |>> ((+) 10)
let length: int option = Some "hello" |>> String.length
// [11; 12; 13] and Some 5
Integrovaná řešení primitivních operátorů si zachovají prioritu pro odpovídající typy. Rozšíření neposkytuje libovolné smíšené rozšíření ani nenahrazuje všechny předdefinované operátory.
Režim F# 11.0 může přijmout běžnou deklaraci operátoru rozšíření s FS1215, ale nemůže ji použít jako řešení SRTP. Projekt operátora používá náhled.
Operátory a kontext řazené kolekce členů
Kolekce pozorování a dvojice nezávisle kumulovaných výsledků se může účastnit stejného kombinovaného protokolu. Následující uživatel definuje svůj obecný algoritmus po otevření adaptérů knihovny:
open Composition.Adapters
open Composition.Algorithms
let inline combineAll (batches: ^T list) : ^T =
List.reduce (++) batches
let observations = combineAll [["temperature"]; ["pressure"; "humidity"]]
let summary = combineAll [(2, ["temperature"]); (3, ["pressure"; "humidity"])]
printfn "%A" observations
printfn "%A" summary
// ["temperature"; "pressure"; "humidity"]
// (5, ["temperature"; "pressure"; "humidity"])
Tato rozšíření knihovny dávají operátoru význam pro celá čísla, seznamy a páry:
type System.Int32 with
static member (++) (left: int, right: int) = left + right
type List<'T> with
static member (++) (left: 'T list, right: 'T list) = left @ right
type ('T1 * 'T2) with
static member inline (++) ((a, b), (c, d)) = (a ++ c, b ++ d)
combineAll vyžaduje neprázdný seznam, protože používá List.reduce. Operace zachovává pořadí seznamu; kompilátor nevynucuje asociativitu ani neposkytuje identitu pro prázdný vstup.
Nativní hlavičky type ('T1 * 'T2) with a type struct ('T1 * 'T2) with rozšíření odkazů CLR a řazených kolekcí hodnot Oba jsou funkce F# 11.2 a podporují dva až sedm prvků; větší hlavičky vytvářejí FS3915.
Řazené kolekce členů můžou mít také kontext spolu s hodnotou. Následující operátor při použití kontextové funkce připojí stopu:
let priced =
(["catalogue price"], fun units -> decimal units * 12m)
<*> (["validated quantity"], 3)
printfn "%A" priced
// (["catalogue price"; "validated quantity"], 36M)
type ('Context * 'Value) with
static member inline (<*>) ((before, mapping), (after, value)) =
(before ++ after, mapping value)
type struct ('Context * 'Value) with
static member inline (<*>) (struct (before, mapping), struct (after, value)) =
struct (before ++ after, mapping value)
Volání dot-instance řazené kolekce členů a nativní hlavičky typu funkce, jako type ('a -> 'b) with například nejsou podporovány.
Knihovna složení i spotřebitel používají náhled. Zachovat combineAll ve spotřebiteli: export této redukce může vytvořit FS0193 pro řazenou kolekci ++členů . Samostatné příklady cest a mapování exportují své algoritmy.
Vrácené konstrukce
U operace, která do kontejneru zavádí prostý údaj, může výstupní typ určit, který člen by měl vytvořit:
type List<'T> with
static member Return(value: 'T) : 'T list = [value]
type Option<'T> with
static member Return(value: 'T) : 'T option = Some value
let inline singleton (value: 'T) : ^Output =
(^Output : (static member Return: 'T -> ^Output) value)
let oneBatch: string list = singleton "ready"
let oneOptional: string option = singleton "ready"
// ["ready"] and Some "ready"
Poznámka k výsledkům příjemce vybere rozšíření výstupního Return typu. Samotný vstup nemůže zvolit kontejner.
Každý kontejner dodává vlastního člena. Pro přetížení jen pro vrácení jednoho typu použijte samostatný AllowOverloadOnReturnType atribut.
Kompilace knihoven a příjemců
Nastavení jazyka platí pro každý projekt, ne tranzitivně prostřednictvím odkazů. Následující matice používá nastavení sady SDK .NET 11.0.100 pro funkce F# 11.2:
| Implementace knihovny | Použití spotřebitele | Požadavek na verzi Preview |
|---|---|---|
| Deklaruje nativní hlavičky rozšíření řazené kolekce členů. | Vyřeší operátory rozšíření. | Oba potřebují verzi Preview; samotná nová syntaxe záhlaví je ve verzi Preview. |
| Definuje běžná rozšíření a exportuje nevyřešené omezení vloženého člena. | Dodává konkrétní typy, jejichž rozšíření toto omezení řeší. | Spotřebitel potřebuje verzi Preview. Knihovna může používat F# 11.0. |
| Řeší omezení rozšíření interně a zveřejňuje běžné nebo již vyřešené vložené rozhraní API. | Volá toto rozhraní API bez dalšího překladu rozšíření. | Knihovna potřebuje náhled; uživatel může použít F# 11.0. |
| Řeší omezení rozšíření a exportů, která příjemce řeší také prostřednictvím rozšíření. | Řeší zbývající omezení. | Oba potřebují náhled. |
Cesta a knihovna mapování používá 11.0; jeho příjemce používá preview. Z adresáře příjemce spusťte dotnet run podporu sady F# 11 SDK.
Obor rozšíření napříč sestaveními
Před definováním závislých vložených funkcí používejte veřejná rozšíření a otevřete jejich modul. U importovaného nevyřešeného omezení také otevřete adaptéry v příjemci; prohlášení výrobce open se nepřenesou. Rozhraní API, které je už vyřešené, nevyžaduje opětovné otevření adaptérů příjemcem.
Odvozování a podpisy
F# 11.2 rozlišení deferuje některé volby, které režim F# 11.0 dělá dříve. Představte si vloženou pomocnou rutinu definovanou příjemcem DateTime :
let inline shift (date: System.DateTime) offset = date + offset
V režimu F# 11.0 může tento formulář odvodit DateTime -> TimeSpan -> DateTime. Pokud je povolené rozlišení rozšíření F# 11.2, může zachovat omezení pro (DateTime or ^Offset) : (static member (+) : DateTime * ^Offset -> ^Result). Příjemce pak může vybrat veřejné rozšíření v oboru pro jiný typ posunu.
Uživatel nemůže obnovit ztracenou generalitu v knihovně F# 11.0. Kontrola exportovaných podpisů; producent může také potřebovat odvozovat F# 11.2.
Omezení verze Preview a řešení potíží
- V případě FS0001 nebo FS0193 zkontrolujte nastavení jazyka, veřejnou viditelnost a obor adaptéru.
- Pokud soubor pozdějšího producenta přeloží příklad
Complexcesty , generování kódu může selhat s FS0971,Undefined value 'get_Coordinates'. Toto řešení ponechte s jeho definicemi nebo v samostatném příjemci. - Konkurenční adaptéry můžou mít nejednoznačný výběr členů.