Closures

Closures are callables that capture variables from the enclosing environment. Both function and operation closures can be created. An operation closure can be created inside a function, but it can only be applied in an operation.

Q# has two mechanisms for creating closures: lambda expressions and partial application.

Lambda expressions

A lambda expression creates an anonymous function or operation. The basic syntax is a symbol tuple to bind the parameters, an arrow (-> for a function and => for an operation), and an expression to evaluate when applied.

// 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 are bound using a symbol tuple that is identical to the left-hand side of a variable declaration statement. The type of the parameter tuple is implicit. Type annotations are not supported; if type inference fails, you may need to create a top-level callable declaration and use partial application instead.

Mutable capture variables

Mutable variables cannot be captured. If you only need to capture the value of a mutable variable at the instant the lambda expression is created, you can create an immutable copy:

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

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

Characteristics

The characteristics of an anonymous operation are inferred based on the applications of the lambda. If the lambda is used with a functor application, or in a context that expects a characteristic, the lambda is then inferred to have that characteristic. For example:

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
}

If you need different characteristics for an operation lambda than what was inferred, you will need to create a top-level operation declaration instead.

Partial application

Partial application is a convenient shorthand for applying some, but not all, of a callable's arguments. The syntax is the same as a call expression, but unapplied arguments are replaced with _. Conceptually, partial application is equivalent to a lambda expression that captures the applied arguments and takes in the unapplied arguments as parameters.

For example, given that f is a function and o is an operation, and the captured variable x is immutable:

Partial application Lambda expression
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 capture variables

Unlike lambda expressions, partial application can automatically capture a copy of the value of a mutable variable:

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

This is equivalent to the following lambda expression:

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

[^1]: The parameter tuple is strictly written (a, (b)), but (b) is equivalent to b.