Замыкания
Замыкания являются вызываемыми объектами, которые захватывают переменные из замыкающей среды. Можно создать как замыкания функций, так и замыкания операций. Замыкание операции можно создать внутри функции, но оно применяется только в операции.
Q# имеет два механизма для создания замыканий: лямбда-выражения и применение частично выполненной строки.
Лямбда-выражения
Лямбда-выражение создает анонимную функцию или операцию.
Базовый синтаксис — это кортеж символов для привязки параметров, стрелка (->
для функции и =>
для операции) и выражение для оценки при применении.
// 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
Параметры
Параметры привязаны с помощью кортежа символов, идентичного левой части оператора объявления переменной. Кортеж параметров имеет неявный тип. Заметки типов не поддерживаются. Если вывод типов завершается сбоем, может потребоваться создать объявление вызываемого объекта верхнего уровня и использовать применение частично выполненной строки.
Изменяемые переменные захвата
Изменяемые переменные нельзя захватывать. Если вам только требуется захватить значение изменяемой переменной в момент создания лямбда-выражения, вы можете создать неизменяемую копию:
// ERROR: 'variable' cannot be captured.
mutable variable = 1;
let f = () -> variable;
// OK.
let value = variable;
let g = () -> value;
Характеристики
Характеристики анонимной операции выводятся на основе применения лямбда-выражения. Если лямбда-выражение используется с приложением функтора или в контексте, который ожидает характеристику, то лямбда-выражение выводится на наличие этой характеристики. Пример:
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
}
Если для лямбда-выражения операции требуются другие характеристики (отличные от выведенных), необходимо создать объявление операции верхнего уровня.
Применение частично выполненной строки
Применение частично выполненной строки — это удобный быстрый способ для применения некоторых (но не всех) аргументов вызываемого объекта.
Синтаксис аналогичен выражению вызова, но аргументы, которые не применяются, заменены на _
.
По своей сути применение частично выполненной строки эквивалентно лямбда-выражению, которое захватывает примененные аргументы и принимает в качестве параметров неприменяемые аргументы.
Например, если f
— это функция, o
— операция, а захваченная переменная x
является неизменяемой:
Применение частично выполненной строки | Лямбда-выражение |
---|---|
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)) |
Изменяемые переменные захвата
В отличие от лямбда-выражений, применение частично выполненной строки может автоматически захватывать копию значения изменяемой переменной:
mutable variable = 1;
let f = Foo(variable, _);
Это эквивалентно следующему лямбда-выражению:
mutable variable = 1;
let value = variable;
let f = x -> Foo(value, x);
[^1]: Кортеж параметров строго записывается как (a, (b))
, но (b)
эквивалентно b
.