Delen via


Sluitingen

Sluitingen zijn aanroepbare variabelen die variabelen uit de omgeving insluiten. Zowel functie- als bewerkingssluitingen kunnen worden gemaakt. Een bewerkingssluiting kan binnen een functie worden gemaakt, maar kan alleen worden toegepast in een bewerking.

Q# heeft twee mechanismen voor het maken van sluitingen: lambda-expressies en gedeeltelijke toepassing.

Lambda-expressies

Een lambda-expressie maakt een anonieme functie of bewerking. De basissyntaxis is een symbool-tuple om de parameters, een pijl (-> voor een functie en => voor een bewerking) te binden en een expressie die moet worden geƫvalueerd wanneer deze wordt toegepast.

// Function that captures 'x':
y -> x + y

// Operation that captures 'qubit':
deg => Rx(deg * PI() / 180.0, qubit)

// Function that captures nothing:
(x, y) -> x + y

Parameterwaarden

Parameters zijn gebonden met behulp van een symbool tuple die identiek is aan de linkerkant van een variabeledeclaratie-instructie. Het type parameter tuple is impliciet. Typeaantekeningen worden niet ondersteund; als het type deductie mislukt, moet u mogelijk een aanroepbare declaratie op het hoogste niveau maken en in plaats daarvan gedeeltelijke toepassing gebruiken.

Veranderlijke capture-variabelen

Veranderlijke variabelen kunnen niet worden vastgelegd. Als u alleen de waarde van een veranderlijke variabele hoeft vast te leggen op het moment dat de lambda-expressie wordt gemaakt, kunt u een onveranderbare kopie maken:

// ERROR: 'variable' cannot be captured.
mutable variable = 1;
let f = () -> variable;

// OK.
let value = variable;
let g = () -> value;

Kenmerken

De kenmerken van een anonieme bewerking worden afgeleid op basis van de toepassingen van de lambda. Als de lambda wordt gebruikt met een functortoepassing, of in een context waarin een kenmerk wordt verwacht, wordt de lambda vervolgens afgeleid om dat kenmerk te hebben. Voorbeeld:

operation NoOp(q : Qubit) : Unit is Adj {}
operation Main() : Unit {
    use q = Qubit();
    let foo = () => NoOp(q);
    foo(); // Has type Unit => Unit with no characteristics

    let bar = () => NoOp(q);
    Adjoint bar(); // Has type Unit => Unit is Adj
}

Als u andere kenmerken nodig hebt voor een bewerkings lambda dan wat is afgeleid, moet u in plaats daarvan een bewerkingsdeclaratie op het hoogste niveau maken.

Gedeeltelijke toepassing

Gedeeltelijke toepassing is een handige afkorting voor het toepassen van sommige, maar niet alle argumenten van een aanroepbare. De syntaxis is hetzelfde als een aanroepexpressie, maar niet-toegepaste argumenten worden vervangen door _. Conceptueel gezien is gedeeltelijke toepassing gelijk aan een lambda-expressie die de toegepaste argumenten vastlegt en de niet-toegepaste argumenten als parameters accepteert.

Aangezien f bijvoorbeeld een functie is en o een bewerking is en de vastgelegde variabele x onveranderbaar is:

Gedeeltelijke toepassing Lambda-expressie
f(x, _) a -> f(x, a)
o(x, _) a => o(x, a)
f(_, (1, _)) (a, b) -> f(a, (1, b))[^1]
f((_, _, x), (1, _)) ((a, b), c) -> f((a, b, x), (1, c))

Veranderlijke capture-variabelen

In tegenstelling tot lambda-expressies kan een gedeeltelijke toepassing automatisch een kopie van de waarde van een veranderlijke variabele vastleggen:

mutable variable = 1;
let f = Foo(variable, _);

Dit komt overeen met de volgende lambda-expressie:

mutable variable = 1;
let value = variable;
let f = x -> Foo(value, x);

[^1]: De parameter tuple is strikt geschreven (a, (b)), maar (b) is gelijk aan b.