Partilhar via


Encerramentos

Os encerramentos são callables que capturam variáveis do ambiente de colocação. Podem ser criados encerramentos de funções e operações. Um encerramento de operação pode ser criado dentro de uma função, mas só pode ser aplicado numa operação.

Q# tem dois mecanismos para criar encerramentos: expressões lambda e aplicação parcial.

Expressões lambda

Uma expressão lambda cria uma função ou operação anónima. A sintaxe básica é uma cadeia de identificação de símbolos para vincular os parâmetros, uma seta (-> para uma função e => para uma operação) e uma expressão a avaliar quando aplicado.

// 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

Parâmetros

Os parâmetros estão vinculados através de uma cadeia de identificação de símbolos idêntica ao lado esquerdo de uma instrução de declaração de variável. O tipo da cadeia de identificação de parâmetros é implícito. As anotações de tipo não são suportadas; Se a inferência do tipo falhar, poderá ter de criar uma declaração callable de nível superior e utilizar a aplicação parcial.

Variáveis de captura mutáveis

Não é possível capturar variáveis mutáveis. Se apenas precisar de capturar o valor de uma variável mutável no instante em que a expressão lambda é criada, pode criar uma cópia imutável:

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

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

Características

As características de uma operação anónima são inferidas com base nas aplicações do lambda. Se o lambda for utilizado com uma aplicação functor ou num contexto que espere uma característica, a lambda é inferida para ter essa característica. Por exemplo:

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
}

Se precisar de características diferentes para uma operação lambda do que as inferidas, terá de criar uma declaração de operação de nível superior.

Aplicação parcial

A aplicação parcial é uma abreviatura conveniente para aplicar alguns argumentos de um callable, mas não todos. A sintaxe é a mesma que uma expressão de chamada, mas os argumentos não aplicados são substituídos _por . Conceptualmente, a aplicação parcial é equivalente a uma expressão lambda que captura os argumentos aplicados e assume os argumentos não aplicados como parâmetros.

Por exemplo, dado que f é uma função e o é uma operação, e a variável x capturada é imutável:

Aplicação parcial Expressão lambda
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))

Variáveis de captura mutáveis

Ao contrário das expressões lambda, a aplicação parcial pode capturar automaticamente uma cópia do valor de uma variável mutável:

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

Isto é equivalente à seguinte expressão lambda:

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

[^1]: A cadeia de identificação do parâmetro é estritamente escrita (a, (b)), mas (b) é equivalente a b.