diff --git a/Specifications/Language/2_Statements/CallStatements.md b/Specifications/Language/2_Statements/CallStatements.md index 1428d1c6..9e87bc7c 100644 --- a/Specifications/Language/2_Statements/CallStatements.md +++ b/Specifications/Language/2_Statements/CallStatements.md @@ -1,6 +1,6 @@ # Call Statements -Call statements are a very important part of any programming language. While operation and function calls, much like [partial applications](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PartialApplication.md#partial-application), can be used as an expression anywhere as long as the returned value is of a suitable type, they can also be used as statements if they return `Unit`. +Call statements are a very important part of any programming language. While operation and function calls can be used as an expression anywhere as long as the returned value is of a suitable type, they can also be used as statements if they return `Unit`. The usefulness of calling functions in this form primarily lays in debugging, whereas such operation calls are one of the most common constructs in any Q# program. At the same time, operations can only be called from within other operations and not from within functions (for context, see also [this section](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/QuantumDataTypes.md#qubits)). With callables being first-class values, diff --git a/Specifications/Language/3_Expressions/Closures.md b/Specifications/Language/3_Expressions/Closures.md new file mode 100644 index 00000000..e171daf5 --- /dev/null +++ b/Specifications/Language/3_Expressions/Closures.md @@ -0,0 +1,118 @@ +# 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. + +```qsharp +// 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](../2_Statements/VariableDeclarationsAndReassignments.md). +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: + +```qsharp +// 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 body of the lambda expression. +For example: + +```qsharp +// Has type Unit => Unit is Adj + Ctl because X is known to be Adj + Ctl. +() => X(q) + + +// Has type Unit => Result because M is neither Adj nor Ctl. +() => M(q) +``` + +Because of limitations in characteristics inference, this is based only on type information known at the point where the lambda expression occurs. +For example: + +```qsharp +let foo = op => op(q); +foo(X); +``` + +`foo` is inferred to have the following type based on both the body of the lambda and the type of `X`: + +```qsharp +(Qubit => Unit is Adj + Ctl) => Unit +``` + +But the most specific type that `foo` could have is: + +```qsharp +(Qubit => Unit is Adj + Ctl) => Unit is Adj + Ctl +``` + +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: + +```qsharp +mutable variable = 1; +let f = Foo(variable, _); +``` + +This is equivalent to the following lambda expression: + +```qsharp +mutable variable = 1; +let value = variable; +let f = x -> Foo(value, x); +``` + +--- + +← [Back to Index](https://github.com/microsoft/qsharp-language/tree/main/Specifications/Language#index) + +[^1]: The parameter tuple is strictly written `(a, (b))`, but [`(b)` is equivalent to `b`](../4_TypeSystem/SingletonTupleEquivalence.md). diff --git a/Specifications/Language/3_Expressions/PartialApplication.md b/Specifications/Language/3_Expressions/PartialApplication.md deleted file mode 100644 index 2a903cd4..00000000 --- a/Specifications/Language/3_Expressions/PartialApplication.md +++ /dev/null @@ -1,14 +0,0 @@ -# Partial Application - -Callables are declared at a global scope and by default can be used anywhere in the same project and in a project that references the assembly in which they are declared. However, often there is a need to construct a callable for use in a local context only. Q# currently provides one rather powerful mechanism to construct new callables on the fly: partial applications. - -Partial application refers to that some of the argument items to a callable are provided while others are still missing as indicated by an underscore. The result is a new callable value that takes the remaining argument items, combines them with the already given ones, and invokes the original callable. Naturally, partial application preserves the characteristics of a callable, i.e. a callable constructed by partial application supports the same functors as the original callable. - -Q# allows any subset of the parameters to be left unspecified, not just a final sequence, which ties in more naturally with the design to have each callable take and return exactly one value. -For a function `Foo` whose argument type is `(Int, (Double, Bool), Int)` for instance, `Foo(_, (1.0, _), 1)` is a function that takes an argument of type `(Int, (Bool))`, which is the same as an argument of type `(Int, Bool)`, see [this section](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/SingletonTupleEquivalence.md#singleton-tuple-equivalence). - -Because partial application of an operation does not actually evaluate the operation, it has -no impact on the quantum state. This means that building a new operation from existing operations and computed data may be done in a function; this is useful in many adaptive quantum algorithms and in defining new control flow constructs. - - -← [Back to Index](https://github.com/microsoft/qsharp-language/tree/main/Specifications/Language#index) \ No newline at end of file diff --git a/Specifications/Language/3_Expressions/ValueLiterals.md b/Specifications/Language/3_Expressions/ValueLiterals.md index ac638d32..a485087e 100644 --- a/Specifications/Language/3_Expressions/ValueLiterals.md +++ b/Specifications/Language/3_Expressions/ValueLiterals.md @@ -138,14 +138,9 @@ Values of a [user defined type](https://github.com/microsoft/qsharp-language/tre For instance, if `IntPair` has two items of type `Int`, then `IntPair(2, 3)` creates a new instance by invoking the default constructor. -## Operation Literals - -No literals exist for values of [operation type](https://github.com/microsoft/qsharp-language/tree/main/Specifications/Language/4_TypeSystem#available-types); operations have to be [declared](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/1_ProgramStructure/3_CallableDeclarations.md#callable-declarations) on a global scope and new operations can be constructed locally using [partial application](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PartialApplication.md#partial-application). - -## Function Literals - -No literals exist for values of [function type](https://github.com/microsoft/qsharp-language/tree/main/Specifications/Language/4_TypeSystem#available-types); functions have to be [declared](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/1_ProgramStructure/3_CallableDeclarations.md#callable-declarations) on a global scope and new functions can be constructed locally using [partial application](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PartialApplication.md#partial-application). +## Operation and Function Literals +Anonymous operations and functions can be created using a [lambda expression](Closures.md#lambda-expressions). ## Default Values diff --git a/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md b/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md index fe0c02df..a395b41c 100644 --- a/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md +++ b/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md @@ -13,7 +13,7 @@ function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit { } ``` -They can be instantiated based on a type parametrized definition such as, e.g., the [type parametrized](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/TypeParameterizations.md#type-parameterizations) function `Pow` above, and they can be [partially applied](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PartialApplication.md#partial-application) as done in Line 2 in the example. +They can be instantiated based on a type parametrized definition such as, e.g., the [type parametrized](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/TypeParameterizations.md#type-parameterizations) function `Pow` above, and they can be [partially applied](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/Closures.md#partial-application) as done in Line 2 in the example. ## Operation Characteristics diff --git a/Specifications/Language/README.md b/Specifications/Language/README.md index ac7e73a0..88729149 100644 --- a/Specifications/Language/README.md +++ b/Specifications/Language/README.md @@ -45,7 +45,7 @@ Q# implements programs in terms of statements and expressions, much like classic 1. [Arithmetic Expressions](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/ArithmeticExpressions.md#arithmetic-expressions) 1. [Concatenations](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/Concatentation.md#concatenation) 1. [Modifiers \& Combinators](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PrecedenceAndAssociativity.md#modifiers-and-combinators) - 1. [Partial Application](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/PartialApplication.md#partial-application) + 1. [Closures](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/Closures.md) 1. [Functor Application](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/FunctorApplication.md#functor-application) 1. [Item Access Expressions](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/ItemAccessExpressions.md#item-access) 1. [Contextual Expressions](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/ContextualExpressions.md#contextual-and-omitted-expressions)