Share via


Aanroepbare declaraties

Aanroepbare declaraties, of aanroepbare declaraties, die zijn gedeclareerd in een globaal bereik, zijn standaard openbaar zichtbaar; Dat wil gezegd dat ze overal in hetzelfde project en in een project kunnen worden gebruikt dat verwijst naar de assembly waarin ze zijn gedeclareerd. Met wijzigingsfuncties voor Access kunt u de zichtbaarheid ervan beperken tot alleen de huidige assembly, zodat implementatiedetails later kunnen worden gewijzigd zonder code te verbreken die afhankelijk is van een specifieke bibliotheek.

Q# ondersteunt twee soorten aanroepbare functies: bewerkingen en functies. In het onderwerp Bewerkingen en functies wordt dieper ingegaan op het onderscheid tussen de twee. Q# ondersteunt ook het definiëren van sjablonen; bijvoorbeeld implementaties met typeparameter voor een bepaald aanroepbaar. Zie Typeparameterisaties voor meer informatie.

Notitie

Dergelijke geparametriseerde implementaties mogen geen taalconstructies gebruiken die afhankelijk zijn van bepaalde eigenschappen van de typeargumenten; er is momenteel geen manier om typebeperkingen uit te drukken in Q#, of om gespecialiseerde implementaties voor bepaalde typeargumenten te definiëren.

Callables en functors

Q# maakt gespecialiseerde implementaties voor specifieke doeleinden mogelijk; Bewerkingen in Q# kunnen bijvoorbeeld impliciet of expliciet ondersteuning voor bepaalde functors definiëren, en ook de gespecialiseerde implementaties die moeten worden aangeroepen wanneer een specifieke functor wordt toegepast op die aanroepbare.

Een functor is in zekere zin een fabriek die een nieuwe aanroepbare implementatie definieert die een specifieke relatie heeft met het aanroepbare waarop deze is toegepast. Functors zijn meer dan traditionele functies op een hoger niveau, omdat ze toegang nodig hebben tot de implementatiedetails van de aanroepbare waarop ze zijn toegepast. In die zin zijn ze vergelijkbaar met andere factory's, zoals sjablonen. Ze kunnen ook worden toegepast op aanroepbare aanroepen met typeparameters.

Overweeg de volgende bewerking, 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]));
            }
        }
    }

Deze bewerking gebruikt een argument van het type Qubit[] en retourneert een waarde van het type Unit. De aantekening is Adj + Ctl in de declaratie van ApplyQFT geeft aan dat de bewerking zowel de Adjoint als de Controlled functor ondersteunt. (Zie Bewerkingskenmerken voor meer informatie). De expressie Adjoint ApplyQFT heeft toegang tot de specialisatie die de aangrenzende implementeert ApplyQFT, en Controlled ApplyQFT heeft toegang tot de specialisatie waarmee de beheerde versie van ApplyQFTwordt geïmplementeerd. Naast het argument van de oorspronkelijke bewerking, gebruikt de gecontroleerde versie van een bewerking een matrix van controle-qubits en past de oorspronkelijke bewerking toe op voorwaarde dat al deze controle-qubits de status |1⟩ hebben.

In theorie moet een bewerking waarvoor een aangrenzende versie kan worden gedefinieerd ook een gecontroleerde versie hebben en vice versa. In de praktijk kan het echter moeilijk zijn om een implementatie voor de een of de ander te ontwikkelen, met name voor probabilistische implementaties volgens een herhalings-tot-succes-patroon. Q# Daarom kunt u ondersteuning voor elke functor afzonderlijk declareren. Omdat de twee functors echter pendelen, moet een bewerking die ondersteuning voor beide definieert, ook een implementatie hebben (meestal impliciet gedefinieerd, wat betekent dat de compiler is gegenereerd) voor wanneer beide functors op de bewerking worden toegepast.

Er zijn geen functors die kunnen worden toegepast op functies. Functies hebben momenteel precies één body-implementatie en geen verdere specialisaties. Bijvoorbeeld de declaratie

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

is gelijk aan

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

body Hier geeft u op dat de opgegeven implementatie van toepassing is op de standaardtekst van de functie Hello, wat betekent dat de implementatie wordt aangeroepen wanneer er geen functors of andere factory-mechanismen zijn toegepast vóór de aanroep. De drie puntjes in body ... komen overeen met een compiler-instructie die aangeeft dat de argumentitems in de functiedeclaratie moeten worden gekopieerd en op deze plek moeten worden geplakt.

De redenen achter expliciet aangeven waar de argumenten van de bovenliggende aanroepbare declaratie moeten worden gekopieerd en geplakt, zijn tweeledig: één, het is niet nodig om de argumentdeclaratie te herhalen en twee, zorgt ervoor dat functors waarvoor extra argumenten nodig zijn, zoals de Controlled functor, op een consistente manier kunnen worden geïntroduceerd.

Wanneer er precies één specialisatie is die de implementatie van de standaardtekst definieert, kan de extra wrapping van het formulier body ... { <implementation> } worden weggelaten.

Recursie

Q# callables kunnen direct of indirect recursief zijn en in elke volgorde worden gedeclareerd; een bewerking of functie kan zichzelf aanroepen of een andere aanroepbare die de aanroeper direct of indirect aanroept.

Wanneer u op kwantumhardware wordt uitgevoerd, kan de stackruimte beperkt zijn en leiden recursies die deze limiet voor stackruimte overschrijden tot een runtimefout.