Udostępnij przez


Wywoływalne deklaracje

Deklaracje z możliwością wywołania lub wywoływane, zadeklarowane w zakresie globalnym są domyślnie widoczne publicznie; oznacza to, że mogą być używane w dowolnym miejscu w tym samym projekcie i w projekcie, który odwołuje się do zestawu, w którym są zadeklarowane. modyfikatory programu Access umożliwiają ograniczenie ich widoczności tylko do bieżącego zestawu, dzięki czemu szczegóły implementacji można zmienić później bez przerywania kodu, który opiera się na określonej bibliotece.

Q# obsługuje dwa rodzaje wywołań: operacje i funkcje. W temacie Operations and Functions opracować różnice między nimi. Q# obsługuje również definiowanie szablonów ; na przykład implementacje sparametryzowane typu dla określonego wywołania. Aby uzyskać więcej informacji, zobacz Type parameterizations.

Uwaga

Takie implementacje sparametryzowane typu mogą nie używać żadnych konstrukcji językowych, które opierają się na określonych właściwościach argumentów typu; Obecnie nie ma możliwości wyrażenia ograniczeń typu w Q#lub definiowania wyspecjalizowanych implementacji dla określonych argumentów typu.

Obiekty wywołujące i funktory

Q# umożliwia wyspecjalizowane implementacje do określonych celów; na przykład operacje w Q# mogą niejawnie lub jawnie definiować obsługę niektórych functors, a także wyspecjalizowane implementacje do wywoływania, gdy określony functor jest stosowany do tego elementu wywołującego.

Functor, w sensie, jest fabryką, która definiuje nową implementację z możliwością wywołania, która ma określony związek z wywoływaną, do którego została zastosowana. Funkcje funktory są bardziej niż tradycyjne funkcje wyższego poziomu, które wymagają dostępu do szczegółów implementacji wywoływanych elementów, do których zostały zastosowane. W tym sensie są one podobne do innych fabryk, takich jak szablony. Można je również stosować do wywoływalnych z parametrami typów.

Rozważ następującą operację, ApplyQFT:

    operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl {
        let length = Length(qs);
        Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1.");
        for i in length - 1..-1..0 {
            H(qs[i]);
            for j in 0..i - 1 {
                Controlled R1Frac([qs[i]], (1, j + 1, qs[i - j - 1]));
            }
        }
    }

Ta operacja przyjmuje argument typu Qubit[] i zwraca wartość typu Unit. Adnotacja is Adj + Ctl w deklaracji ApplyQFT wskazuje, że operacja obsługuje zarówno Adjoint, jak i Controlled functor. (Aby uzyskać więcej informacji, zobacz Właściwości operacji). Wyrażenie Adjoint ApplyQFT uzyskuje dostęp do specjalizacji, która implementuje przyleganie ApplyQFT, a Controlled ApplyQFT uzyskuje dostęp do specjalizacji, która implementuje kontrolowaną wersję ApplyQFT. Oprócz argumentu oryginalnej operacji kontrolowana wersja operacji przyjmuje tablicę kubitów sterujących i stosuje oryginalną operację pod warunkiem, że wszystkie te kubity sterujące znajdują się w stanie |1⟩.

Teoretycznie operacja, dla której można zdefiniować wersję przyleganą, powinna mieć również kontrolowaną wersję i odwrotnie. W praktyce jednak może być trudno opracować implementację dla jednej lub drugiej, zwłaszcza w przypadku implementacji probabilistycznej po wzorzec powtarzania do sukcesu. Z tego powodu Q# umożliwia deklarowanie obsługi poszczególnych functor indywidualnie. Jednak ze względu na to, że dwie funktory dojeżdżają do pracy, operacja definiująca obsługę obu elementów również musi mieć implementację (zwykle zdefiniowaną niejawnie, co oznacza generowanie kompilatora) w przypadku zastosowania obu elementów functor do operacji.

Nie ma żadnych funktorów, które można zastosować do funkcji. Funkcje mają obecnie dokładnie jedną implementację treści i nie ma dalszych specjalizacji. Na przykład deklaracja

    function Hello (name : String) : String {
        $"Hello, {name}!"
    }

jest odpowiednikiem

    function Hello (name : String) : String {
        body ... {
            $"Hello, {name}!"
        }
    }

W tym miejscu body określa, że dana implementacja ma zastosowanie do domyślnej treści funkcji Hello, co oznacza, że implementacja jest wywoływana, gdy przed wywołaniem nie zastosowano żadnych elementów funktorowych ani innych mechanizmów fabrycznych. Trzy kropki w body ... odpowiadają dyrektywie kompilatora wskazującej, że elementy argumentu w deklaracji funkcji powinny być kopiowane i wklejane do tego miejsca.

Przyczyny jawnego wskazania, gdzie argumenty deklaracji z możliwością wywołania nadrzędnego mają zostać skopiowane i wklejone, to dwa: jedno, niepotrzebne jest powtórzenie deklaracji argumentu i dwa, gwarantuje, że functory, które wymagają dodatkowych argumentów, takich jak Controlled functor, można wprowadzić w spójny sposób.

Jeśli istnieje dokładnie jedna specjalizacja definiująca implementację treści domyślnej, dodatkowe zawijanie formularza body ... { <implementation> } może zostać pominięte.

Rekursja

Q# wywołania mogą być bezpośrednio lub pośrednio rekursywne i mogą być deklarowane w dowolnej kolejności; operacja lub funkcja może wywołać samą siebie lub wywołać inną metodę wywołującą, która bezpośrednio lub pośrednio wywołuje obiekt wywołujący.

Przestrzeń stosu może być ograniczona podczas uruchamiania na sprzęcie kwantowym, a rekursje, które przekraczają ten limit miejsca na stosie, powodują błąd środowiska uruchomieniowego.