Dela via


Anropningsbara deklarationer

Anropsbara deklarationer, eller anropbara värden, som deklareras i ett globalt omfång är offentligt synliga som standard. De kan alltså användas var som helst i samma projekt och i ett projekt som refererar till den sammansättning där de deklareras. Med åtkomstmodifierare kan du begränsa deras synlighet till den aktuella sammansättningen, så att implementeringsinformationen kan ändras senare utan att kod som förlitar sig på ett visst bibliotek bryts.

Q# stöder två typer av anropbara: åtgärder och funktioner. I avsnittet Åtgärder och funktioner beskrivs skillnaden mellan de två. Q# stöder också definition av mallar. Till exempel typparameteriserade implementeringar för en viss anropningsbar. Mer information finns i Type parameterizations (Typparameteriseringar).

Anteckning

Sådana typparmetriserade implementeringar får inte använda några språkkonstruktioner som förlitar sig på särskilda egenskaper hos typargumenten. Det finns för närvarande inget sätt att uttrycka typbegränsningar i Q#, eller att definiera specialiserade implementeringar för specifika typargument.

Callables och functors

Q# tillåter särskilda implementeringar för specifika ändamål. Till exempel kan åtgärder i Q# implicit eller explicit definiera stöd för vissa funktorer, och tillsammans med det de specialiserade implementeringar som ska anropas när en specifik functor tillämpas på den anropsbara.

En functor är på sätt och vis en fabrik som definierar en ny anropsbar implementering som har en specifik relation till den anropsbara som den tillämpades på. Functors är mer än traditionella funktioner på högre nivå eftersom de kräver åtkomst till implementeringsinformationen för de anropbara funktioner som de har tillämpats på. I den meningen liknar de andra fabriker, till exempel mallar. De kan även tillämpas på typparameteriserade anropsbara objekt.

Överväg följande åtgärd: 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]));
            }
        }
    }

Den här åtgärden tar ett argument av typen Qubit[] och returnerar ett värde av typen Unit. is Adj + Ctl Kommentaren i deklarationen av ApplyQFT anger att åtgärden stöder både Adjoint - och Controlled -funktor. (Mer information finns i Driftegenskaper). Uttrycket Adjoint ApplyQFT kommer åt specialiseringen som implementerar angränsande ApplyQFTtill och Controlled ApplyQFT använder specialiseringen som implementerar den kontrollerade versionen av ApplyQFT. Förutom den ursprungliga åtgärdens argument tar den kontrollerade versionen av en åtgärd en matris med kontrollkvenbitar och tillämpar den ursprungliga åtgärden på villkoret att alla dessa kontrollkvenbitar är i tillståndet |1⟩.

I teorin bör en åtgärd för vilken en angränsande version kan definieras också ha en kontrollerad version och vice versa. I praktiken kan det dock vara svårt att utveckla en implementering för den ena eller den andra, särskilt för probabilistiska implementeringar efter ett upprepnings-till-framgång-mönster. Av den anledningen Q# kan du deklarera stöd för varje functor individuellt. Men eftersom de två funktorerna pendlar måste en åtgärd som definierar stöd för båda också ha en implementering (vanligtvis implicit definierad, vilket innebär kompilatorgenererad) för när båda functors tillämpas på operationen.

Det finns inga funktorer som kan tillämpas på funktioner. Funktioner har för närvarande exakt en kroppsimplementering och inga ytterligare specialiseringar. Deklarationen kan till exempel

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

motsvarar

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

body Här anger att den angivna implementeringen gäller för standardtexten i funktionen Hello, vilket innebär att implementeringen anropas när inga funktorer eller andra fabriksmekanismer har tillämpats före anropet. De tre punkterna i body ... motsvarar ett kompilatordirektiv som anger att argumentobjekten i funktionsdeklarationen ska kopieras och klistras in på den här platsen.

Orsakerna bakom som uttryckligen anger var argumenten för den överordnade anropningsbara deklarationen ska kopieras och klistras in är två: ett, det är onödigt att upprepa argumentdeklarationen och två, det säkerställer att funktorer som kräver ytterligare argument, som Controlled functor, kan introduceras på ett konsekvent sätt.

När det finns exakt en specialisering som definierar implementeringen av standardtexten kan ytterligare omslutning av formuläret body ... { <implementation> } utelämnas.

Rekursion

Q# callables kan vara direkt eller indirekt rekursiv och kan deklareras i vilken ordning som helst; en åtgärd eller funktion kan anropa sig själv eller anropa en annan anropsbar som direkt eller indirekt anropar anroparen.

När du kör på kvantmaskinvara kan stackutrymmet vara begränsat, och rekursioner som överskrider den stackutrymmesgränsen resulterar i ett körningsfel.