Sdílet prostřednictvím


Podtypy a variance

Q# podporuje pouze několik mechanismů převodu. K implicitním převodům může dojít pouze při použití binárních operátorů, vyhodnocování podmíněných výrazů nebo při vytváření literálu pole. V těchto případech se určí běžný supertyp a potřebné převody se provádějí automaticky. Kromě těchto implicitních převodů jsou možné a často nezbytné explicitní převody prostřednictvím volání funkcí.

V současné době platí pro operace jediný existující vztah podtypů. Intuitivně dává smysl, aby jedna z nich nahradila operaci, která podporuje více než požadovanou sadu funktorů. Konkrétně pro jakékoli dva konkrétní typy TIn a TOut, je vztah podtypu

    (TIn => TOut) :>
    (TIn => TOut is Adj), (TIn => TOut is Ctl) :>
    (TIn => TOut is Adj + Ctl)

kde A :> B označuje, že B je podtyp .A Formulace odlišně, B je více omezující než A takový, že hodnota typu B může být použita všude, kde je požadována hodnota typu A . Pokud volatelný argument závisí na argumentu (položce) typu A, může být argument typu B bezpečně nahrazen, protože pokud poskytuje všechny potřebné funkce.

Tento druh polymorfismu se vztahuje na řazené kolekce členů v tom, že kolekce členů typu B je podtypem typu A řazené kolekce členů, pokud obsahuje stejný počet položek a typ každé položky je podtyp odpovídajícího typu položky v A. To se označuje jako podtypy hloubky. V současné době neexistuje podpora podtypů šířky, to znamená, že neexistuje žádný vztah podtypu mezi dvěma typy definovanými uživatelem nebo uživatelem definovaným typem a jakýmkoli předdefinovaný typ. Tomu brání existence operátoru unwrap , který umožňuje extrahovat kolekci členů obsahující všechny pojmenované a anonymní položky.

Poznámka

Pokud jde o volatelné položky, zpracovává-li volatelný argument typu A, je také schopen zpracovat argument typu B. Pokud se volatelný argument předá jinému volatelnému, musí být schopen zpracovat vše, co může podpis typu vyžadovat. To znamená, že pokud volatelný potřebuje být schopen zpracovat argument typu B, lze bezpečně předat jakýkoli volatelný argument, který je schopen zpracovat obecnější argument typu A . Naopak očekáváme, že pokud požadujeme, aby předaná volatelná vrátila hodnotu typu A, pak je příslib vrácení hodnoty typu B dostačující, protože tato hodnota poskytne všechny potřebné funkce.

Operace nebo typ funkce je kontravariantní ve svém typu argumentu a kovariantní ve návratovém typu. A :> B z toho vyplývá, že pro jakýkoli typ betonu T1,

    (B → T1) :> (A → T1), and
    (T1 → A) :> (T1 → B) 

kde zde může znamenat buď funkci, nebo operaci, a vynecháme všechny poznámky k charakteristikám. Nahrazení a (T2 → A) v uvedeném pořadí a nahrazení B(A → T2) a (T2 → B) v uvedeném pořadí vede k závěru, že pro každý typ betonu T2,A(B → T2)

    ((A → T2) → T1) :> ((B → T2) → T1), and
    ((T2 → B) → T1) :> ((T2 → A) → T1), and
    (T1 → (B → T2)) :> (T1 → (A → T2)), and
    (T1 → (T2 → A)) :> (T1 → (T2 → B)) 

Z indukce vyplývá, že každá další zprostředkuje odchylku typu argumentu a ponechá rozptyl návratového typu beze změny.

Poznámka

To také jasně vysvětluje, jaké rozptylové chování polí musí být; načítání položek prostřednictvím operátoru přístupu k položkám odpovídá vyvolání funkce typu (Int -> TItem), kde TItem je typ prvků v poli. Vzhledem k tomu, že tato funkce je implicitně předána při předávání pole, z toho vyplývá, že pole musí být kovariantní ve svém typu položky. Stejné aspekty platí i pro řazené kolekce členů, které jsou neměnné a proto kovariantní vzhledem ke každému typu položky. Pokud by pole nebyla neměnná, existence konstruktoru, který by vám umožnil nastavit položky v matici, a tedy přijmout argument typu TItem, by znamenala, že pole musí být také kontravariantní. Jedinou možností pro datové typy, které podporují získávání a nastavení položek, je tedy invariantní, což znamená, že neexistuje žádný vztah podtypů; B[]není podtyp , A[] i když B je podtyp .A Navzdory skutečnosti, že pole v Q# souboru jsou neměnná, jsou spíše invariantní než kovariantní. To například znamená, že hodnotu typu (Qubit => Unit is Adj)[] nelze předat volatelné hodnotě, která vyžaduje argument typu (Qubit => Unit)[]. Zachování invariantní matice umožňuje větší flexibilitu související s tím, jak jsou pole zpracovávána a optimalizována v modulu runtime, ale v budoucnu může být možné to změnit.