From 1922e8417e7f48a40e838a7e3c9e03cc51380fd2 Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 12 Jan 2021 12:51:31 -0800 Subject: [PATCH 1/2] Update spec for parentheses that are now optional --- .../Language/2_Statements/CallStatements.md | 4 ++-- .../3_Expressions/ConditionalExpressions.md | 12 ++++++------ .../3_Expressions/PrecedenceAndAssociativity.md | 13 ++++++------- .../Language/4_TypeSystem/OperationsAndFunctions.md | 10 +++++----- .../Language/4_TypeSystem/TypeParameterizations.md | 8 ++++---- 5 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Specifications/Language/2_Statements/CallStatements.md b/Specifications/Language/2_Statements/CallStatements.md index 41a7c02..1df4526 100644 --- a/Specifications/Language/2_Statements/CallStatements.md +++ b/Specifications/Language/2_Statements/CallStatements.md @@ -8,8 +8,8 @@ call statements in a sense are the generic way of supporting patterns that aren' ```qsharp operation ApplyWithInputTransformation<'TArg, 'TIn>( - fn : ('TIn -> 'TArg), - op : ('TArg => Unit), + fn : 'TIn -> 'TArg, + op : 'TArg => Unit, input : 'TIn ) : Unit { diff --git a/Specifications/Language/3_Expressions/ConditionalExpressions.md b/Specifications/Language/3_Expressions/ConditionalExpressions.md index 90df5c1..96967c3 100644 --- a/Specifications/Language/3_Expressions/ConditionalExpressions.md +++ b/Specifications/Language/3_Expressions/ConditionalExpressions.md @@ -11,15 +11,15 @@ For instance, in an expression `a == b ? C(qs) | D(qs)`, if `a` equals `b` then The types of the `ifTrue` and the `ifFalse` expression have to have a [common base type](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/SubtypingAndVariance.md#subtyping-and-variance). Independent of which one of the two ultimately yields the value to which the expression evaluates, its type will always match the determined base type. For example, if -- `Op1` is of type `(Qubit[] => Unit is Adj)` -- `Op2` is of type `(Qubit[] => Unit is Ctl)` -- `Op3` is of type `(Qubit[] => Unit is Adj + Ctl)` +- `Op1` is of type `Qubit[] => Unit is Adj` +- `Op2` is of type `Qubit[] => Unit is Ctl` +- `Op3` is of type `Qubit[] => Unit is Adj + Ctl` then -- `cond ? Op1 | Op2` is of type `(Qubit[] => Unit)` -- `cond ? Op1 | Op3` is of type `(Qubit[] => Unit is Adj)` -- `cond ? Op2 | Op3` is of type `(Qubit[] => Unit is Ctl)` +- `cond ? Op1 | Op2` is of type `Qubit[] => Unit` +- `cond ? Op1 | Op3` is of type `Qubit[] => Unit is Adj` +- `cond ? Op2 | Op3` is of type `Qubit[] => Unit is Ctl` See the section on [subtyping](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/4_TypeSystem/SubtypingAndVariance.md#subtyping-and-variance) for more detail. diff --git a/Specifications/Language/3_Expressions/PrecedenceAndAssociativity.md b/Specifications/Language/3_Expressions/PrecedenceAndAssociativity.md index be48526..edcd3e5 100644 --- a/Specifications/Language/3_Expressions/PrecedenceAndAssociativity.md +++ b/Specifications/Language/3_Expressions/PrecedenceAndAssociativity.md @@ -48,7 +48,7 @@ This artificial precedence is listed in the table below, which also shows how th | Description | Syntax | Operator | Associativity | Precedence | | --- | --- | --- | --- | --- | -| [Call combinator](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/2_Statements/CallStatements.md#call-statements) | `(` `)` | n/a | right | 900 | +| [Call combinator](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/2_Statements/CallStatements.md#call-statements) | `(` `)` | n/a | left | 900 | | [Adjoint functor](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/2_Statements/CallStatements.md#call-statements) | `Adjoint` | prefix | right | 950 | | [Controlled functor](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/2_Statements/CallStatements.md#call-statements) | `Controlled` | prefix | right | 950 | | [Unwrap application](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/3_Expressions/ItemAccessExpressions.md#item-access-for-user-defined-types) | `!` | postfix | left | 1000 | @@ -64,15 +64,14 @@ To illustrate the implications of the assigned precedences, suppose we have a un Apply : Transformation ); - newtype Transformation = ( - LittleEndian => Unit is Adj + Ctl - ); + newtype Transformation = + LittleEndian => Unit is Adj + Ctl; ``` where `LittleEndian` is defined in [this section](https://github.com/microsoft/qsharp-language/blob/main/Specifications/Language/1_ProgramStructure/2_TypeDeclarations.md#type-declarations). Then the following expressions are all valid: ```qsharp - (GetStatePrep())(arg) + GetStatePrep()(arg) (Transformation(GetStatePrep()))!(arg) Adjoint DoNothing() Controlled Adjoint DoNothing(cs, ()) @@ -80,8 +79,8 @@ Then the following expressions are all valid: algorithms[0]::Register![i] ``` Looking at the precedences defined in the table above, we see that the parentheses around `(Transformation(GetStatePrep()))` are necessary for the subsequent unwrap operator to be applied to the `Transformation` value rather than the returned operation. -Similarly, the syntax `GetStatePrep()(arg)` doesn't lead to a valid expression; parenthesis are required around the `GetStatePrep` call in order to invoke the returned callable. -Functor applications on the other hand don't require parentheses around them in order to invoke the corresponding specialization. Neither do array or named item access expressions, such that an expression `arr2D[i][j]` is perfectly valid, just like `algorithms[0]::Register![i]` is. +However, parentheses are not required in `GetStatePrep()(arg)`; functions are applied left-to-right, so this expression is equivalent to `(GetStatePrep())(arg)`. +Functor applications also don't require parentheses around them in order to invoke the corresponding specialization. Neither do array or named item access expressions, such that an expression `arr2D[i][j]` is perfectly valid, just like `algorithms[0]::Register![i]` is. ← [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/4_TypeSystem/OperationsAndFunctions.md b/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md index 0660681..9be2dcc 100644 --- a/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md +++ b/Specifications/Language/4_TypeSystem/OperationsAndFunctions.md @@ -4,13 +4,13 @@ As elaborated in more detail in the description of the [qubits](https://github.c Q# allows to explicitly split out such purely deterministic computations into *functions*. Since the set of natively supported instructions is not fixed and built into the language itself, but rather fully configurable and expressed as a Q# library, determinism is guaranteed by requiring that functions can only call other functions, but cannot call any operations. Additionally, native instructions that are not deterministic, e.g., because they impact the quantum state are represented as operations. With these two restrictions, function can be evaluated as soon as their input value is known, and in principle never need to be evaluated more than once for the same input. -Q# therefore distinguishes between two types of callables: operations and functions. All callables take a single (potentially tuple-valued) argument as input and produce a single value (tuple) as output. Syntactically, the operation type is expressed as `( => is )`, where `` is to be replaced by the argument type, `` is to be replaced by the return type, and `` is to be replaced by the [operation characteristics](#operation-characteristics). If no characteristics need to be specified, the syntax simplifies to `( => )`. Similarly, function types are expressed as `( -> )`. +Q# therefore distinguishes between two types of callables: operations and functions. All callables take a single (potentially tuple-valued) argument as input and produce a single value (tuple) as output. Syntactically, the operation type is expressed as ` => is `, where `` is to be replaced by the argument type, `` is to be replaced by the return type, and `` is to be replaced by the [operation characteristics](#operation-characteristics). If no characteristics need to be specified, the syntax simplifies to ` => `. Similarly, function types are expressed as ` -> `. There is little difference between operations and functions beside this determinism guarantee. Both are first-class values that can be passed around freely; they can be used as return values or arguments to other callables, as illustrated by the example below. ```qsharp - function Pow<`T>(op:(`T => Unit, pow : Int) : (`T => Unit){ - return PowImpl(op, pow, _); - } +function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit { + return PowImpl(op, pow, _); +} ``` 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. @@ -36,7 +36,7 @@ In EBNF, | "(", characteristics, ")" | characteristics ("+"|"*") characteristics; ``` -As one would expect, `*` has higher precedence than `+` and both are left-associative. The type of a unitary operation for example is expressed as `( => is Adj + Ctl)` where `` should be replace with the type of the operation argument, and `` with the type of the returned value. +As one would expect, `*` has higher precedence than `+` and both are left-associative. The type of a unitary operation for example is expressed as ` => is Adj + Ctl` where `` should be replaced with the type of the operation argument, and `` with the type of the returned value. ### *Discussion* >Indicating the characteristics of an operation in this form has two major advantages; for one, new labels can be introduced without having exponentially many language keywords for all combinations of labels. Perhaps more importantly, using expressions to indicate the characteristics of an operation also permits to support parameterizations over operation characteristics in the future. diff --git a/Specifications/Language/4_TypeSystem/TypeParameterizations.md b/Specifications/Language/4_TypeSystem/TypeParameterizations.md index ab3c568..406a31f 100644 --- a/Specifications/Language/4_TypeSystem/TypeParameterizations.md +++ b/Specifications/Language/4_TypeSystem/TypeParameterizations.md @@ -12,7 +12,7 @@ A type parametrized callable needs to be concretized — i.e. provided with the ```qsharp function Mapped<'T1, 'T2> ( - mapper : ('T1 -> 'T2), + mapper : 'T1 -> 'T2, array : 'T1[] ) : 'T2[] { @@ -31,11 +31,11 @@ A type parametrized callable needs to be concretized — i.e. provided with the } ``` -The function `CControlled` is defined in the `Microsoft.Quantum.Canon` namespace. It takes an operation `op` of type `('TIn => Unit)` as argument and returns a new operation of type `((Bool, 'TIn) => Unit)` that applies the original operation provided a classical bit (of type `Bool`) is set to true; this is often referred to as the classically controlled version of `op`. +The function `CControlled` is defined in the `Microsoft.Quantum.Canon` namespace. It takes an operation `op` of type `'TIn => Unit` as argument and returns a new operation of type `(Bool, 'TIn) => Unit` that applies the original operation provided a classical bit (of type `Bool`) is set to true; this is often referred to as the classically controlled version of `op`. The function `Mapped` takes an array of an arbitrary item type `'T1` as argument, applies the given `mapper` function to each item and returns a new array of type `'T2[]` containing the mapped items. It is defined in the `Microsoft.Quantum.Array` namespace. For the purpose of the example, the type parameters are numbered to avoid making the discussion more confusing by giving the type parameters in both functions the same name. This is not necessary; type parameters for different callables may have the same name, and the chosen name is only visible and relevant within the definition of that callable. -The function `AllCControlled` takes an array of operations and returns a new array containing the classically controlled versions of these operations. The call of `Mapped` resolves its type parameter `'T1` to `('T3 => Unit)`, and its type parameter `'T2` to `((Bool,'T3) => Unit)`. The resolving type arguments are inferred by the compiler based on the type of the given argument. We say that they are *implicitly* defined by the argument of the call expression. Type arguments can also be specified explicitly as it is done for `CControlled` in the same line. The explicit concretization `CControlled<'T3>` is necessary when the type arguments cannot be inferred. +The function `AllCControlled` takes an array of operations and returns a new array containing the classically controlled versions of these operations. The call of `Mapped` resolves its type parameter `'T1` to `'T3 => Unit`, and its type parameter `'T2` to `(Bool,'T3) => Unit`. The resolving type arguments are inferred by the compiler based on the type of the given argument. We say that they are *implicitly* defined by the argument of the call expression. Type arguments can also be specified explicitly as it is done for `CControlled` in the same line. The explicit concretization `CControlled<'T3>` is necessary when the type arguments cannot be inferred. The type `'T3` is concrete within the context of `AllCControlled`, since it is known for each *invocation* of `AllCControlled`. That means that as soon as the entry point of the program - which cannot be type parametrized - is know, so is the concrete type `'T3` for each call to `AllCControlled`, such that a suitable implementation for that particular type resolution can be generated; once the entry point to a program is known, all usages of type parameters can be eliminated at compile-time. We refer to this process as *monomorphization*. @@ -46,7 +46,7 @@ A couple of restrictions are needed to ensure that this can indeed be done at co > >```qsharp > operation Foo<'TArg> ( -> op : ('TArg => Unit), +> op : 'TArg => Unit, > arg : 'TArg > ) : Unit { > From 02980d948e825f812797053791018cd7129faeca Mon Sep 17 00:00:00 2001 From: Sarah Marshall Date: Tue, 12 Jan 2021 12:56:04 -0800 Subject: [PATCH 2/2] Remove required parens from callable types in grammar --- Specifications/Language/5_Grammar/QSharpParser.g4 | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Specifications/Language/5_Grammar/QSharpParser.g4 b/Specifications/Language/5_Grammar/QSharpParser.g4 index ca91aa7..2722860 100644 --- a/Specifications/Language/5_Grammar/QSharpParser.g4 +++ b/Specifications/Language/5_Grammar/QSharpParser.g4 @@ -111,7 +111,10 @@ specializationParameter type : '_' + | '(' (type (',' type)* ','?)? ')' | TypeParameter + | type '[' ']' + | type ('->' | '=>') type characteristics? | 'BigInt' | 'Bool' | 'Double' @@ -123,14 +126,6 @@ type | 'String' | 'Unit' | qualifiedName - | '(' (type (',' type)* ','?)? ')' - | '(' arrowType characteristics? ')' - | type '[' ']' - ; - -arrowType - : '(' type ('->' | '=>') type ')' - | type ('->' | '=>') type ; // Statement