Sluitingen
Sluitingen zijn aanroepbare apparaten die variabelen uit de omringende omgeving vastleggen. Zowel functie- als bewerkingssluitingen kunnen worden gemaakt. Een bewerkingssluiting kan worden gemaakt in een functie, 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 te binden, een pijl (->
voor een functie en =>
voor een bewerking) 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
Parameters
Parameters worden gebonden met behulp van een symbool-tuple die identiek is aan de linkerkant van een variabeledeclaratie-instructie. Het type van de parameter-tuple is impliciet. Typeaantekeningen worden niet ondersteund; Als type deductie mislukt, moet u mogelijk een aanroepbare declaratie op het hoogste niveau maken en in plaats daarvan een gedeeltelijke toepassing gebruiken.
Veranderlijke vastlegvariabelen
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 die een kenmerk verwacht, wordt de lambda vervolgens afgeleid om dat kenmerk te hebben. Bijvoorbeeld:
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 voor een bewerkingslamda andere kenmerken nodig hebt 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 aanroepbaar.
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 opneemt.
Bijvoorbeeld, aangezien f
het 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 vastlegvariabelen
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
.