表达式
分组
给定任何表达式,括在圆括号中的相同表达式是相同类型的表达式。 例如, (7)
是一个Int
表达式, ([1;2;3])
是Int
类型数组的表达式, ((1,2))
是类型为(Int, Int)
的表达式。
在类型模型中描述的简单值和单元素元组之间的等价性消除了(6)
作为一个组和(6)
作为单元素元组之间的歧义。
符号
绑定或分配给类型'T
值的符号的名称是'T
类型的表达式。 例如,如果符号count
绑定到整数值5
,则count
是一个整数表达式。
数字表达式
数字表达式是Int
或Double
类型的表达式。 也就是说,它们可以是整数或浮点数。
Q#中的Int
文字与C#中的整数文字相同,不同之处在于不需要(或允许)结尾的“l”或“L”。 前缀“0x”支持十六进制整数。
Q#中的双字面值与C#中的双字面值相同,不同之处在于不需要(或允许)结尾的“d”或“D”。
给定任何元素类型的数组表达式,可以使用Length
内置函数形成一个Int
表达式,并将数组表达式放在圆括号(
和)
。 例如,如果将a
绑定到数组,则Length(a)
是一个整数表达式。 如果b
是整数数组Int[][]
,那么Length(b)
是Length(b)
中子数组的数量, Length(b[1])
是第二个子数组中的整数数在b
。
给定两个数字表达式,二元运算符+
, -
, *
和/
可用于形成新的数字表达式。 如果两个构成表达式都是Double
,则新表达式的类型将为Double
如果两个构成表达式都是整数,则它们将是一个Int
表达式。
给定两个整数表达式,可以使用%
(模数), ^
(power), &&&
(按位AND), |||
(按位OR), ^^^
(按位XOR), <<<
(算术左移)或>>>
(算术右移)操作。 要么进行换档操作的第二个参数必须大于或等于零。 转移负数的行为是未定义的。
整数除法和整数模数遵循与C#一样的负数相同的行为。 也就是说, a % b
将始终与b * (a / b) + a % b
具有相同的符号,并且b * (a / b) + a % b
将始终等于a
。 例如:
A | B | A / B | A % B |
---|---|---|---|
五 | 2 | 2 | 1 |
五 | -2 | -2 | 1 |
-5 | 2 | -2 | -1 |
-5 | -2 | 2 | -1 |
给定任何数字表达式,可以使用-
一元运算符形成新的表达式。 新表达式将与组成表达式的类型相同。
给定任何整数表达式,可以使用~~~
(按位互补)一元运算符形成新的整数表达式。
Qubit表达式
唯一的量子位表达式是与量子位数组或量子位数组元素绑定的符号。 没有量子比特文字。
泡利表达式
Pauli
四, PauliX
, PauliY
和PauliZ
都是有效的Pauli
表达。
除此之外,唯一的Pauli
表达式是与Pauli
数组或Pauli
数组的数组元素绑定的符号。
结果表达式
两个Result
值One
和Zero
是有效的Result
表达式。
除此之外,唯一的Result
表达式是绑定到Result
数组或Result
数组的数组元素的符号。 尤其要注意的是, One
与整数1
不一样,并且它们之间没有直接转换。 Zero
和0
也是如此。
范围表达式
给定任意三个Int
表达式start
, step
和stop
, start .. step .. stop
是一个范围表达式,其第一个元素是start
,第二个元素是start+step
,第三个元素是start+step+step
等,直到stop
已通过。 例如,如果step
为正并且stop < start
,则范围可以是空的。 如果start
和stop
之间的差值是step
的整数倍,范围的最后一个元素将stop
; 也就是说,范围在两端都包含在内。
给定任意两个Int
表达式start
和stop
, start .. stop
是一个等于start .. 1 .. stop
的范围表达式start .. 1 .. stop
。 请注意,即使stop
小于start
,隐含step
为+1, 在这种情况下,范围是空的。
一些示例范围是:
-
1..3
是范围1,2,3。 -
2..2..5
是范围2,4。 -
2..2..6
是范围2,4,6。 -
6..-2..2
是范围6..-2..2
。 -
2..1
是空的范围。 -
2..6..7
是范围2。 -
2..2..1
是空的范围。 -
1..-1..2
是空的范围。
可调用的表达式
可调用文字是在编译范围中定义的操作或函数的名称。 例如, X
是引用标准库X
操作的操作文字,而Message
是引用标准库Message
函数的函数文字。
如果操作支持Adjoint
函子,则(Adjoint op)
是一个运算表达式。 同样,如果操作支持Controlled
仿函数,则(Controlled op)
是操作表达式。 这些表达式的类型在上面的Functors中指定。
可调用的调用表达式
给定可调用(操作或函数)表达式和可调用签名的输入类型的元组表达式,可以通过将元组表达式附加到可调用表达式来形成调用表达式。 调用表达式的类型是可调用签名的输出类型。
例如,如果Op
是具有签名((Int, Qubit) => Double)
Op(3, qubit1)
,则Op(3, qubit1)
是Double
类型的表达式。 同样,如果Sin
是具有签名的函数(Double -> Double)
,则Sin(0.1)
是Double
类型的表达式。
调用可调用值表达式的结果需要在可调用表达式附近添加一对额外的括号。 因此,为了从前一段调用Op
的伴随,正确的语法是:
(Adjoint(Op))(3, qubit1)
部分应用
给定可调用的表达式,可以通过向可调用对象提供参数的子集来创建新的可调用对象。 这被称为部分应用程序 。
在Q#中,部分应用的可调用是通过编写一个普通的调用表达式来表达的,但对未指定的参数使用下划线_
。 结果可调用的结果类型与基本可调用结果类型相同,并且操作的变量也相同。 部分应用程序的输入类型只是删除了指定参数的原始类型。
如果在创建部分应用程序时将可变变量作为指定参数传递,则会使用该变量的当前值。 之后更改变量的值不会影响部分应用程序。
例如,如果Op
有类型((Int, ((Qubit,Qubit), Double)) => ():Adjoint)
:
-
Op(5,(_,_))
有类型(((Qubit,Qubit), Double) => ():Adjoint)
,Op(5,_)
。 -
Op(_,(_,1.0))
有类型((Int, (Qubit,Qubit)) => ():Adjoint)
。 -
Op(_,((q1,q2),_))
具有类型((Int,Double) => ():Adjoint)
。 请注意,我们在这里应用了单例元组等价。
递归
Q#可调参数允许直接或间接递归。 也就是说,一个操作或函数可能会调用它自己,或者它可能会调用另一个直接或间接调用可调用操作的可调用对象。
然而,有关使用递归的两个重要评论:
- 在操作中使用递归可能会干扰某些优化。 这可能会对算法的执行时间产生重大影响。 如果阻止优化,编译器应该生成警告。
- 在实际量子器件上执行时,堆栈空间可能会受到限制,因此深度递归可能会导致运行时错误。 特别是,Q#编译器和运行时不会识别和优化尾递归。
元组表达式
元组文字是一系列适当类型的元素表达式,用逗号分隔,并用(
和)
括起来。 例如, (1, One)
是一个(Int, Result)
表达式。
除文字外,唯一的元组表达式是绑定到元组值的符号,元组数组的元素元素和返回元组的可调用调用。
用户定义的类型表达式
用户定义类型的文字由类型名称组成,后跟类型的基本元组类型的元组文字。 例如,如果IntPair
是基于(Int, Int)
的用户定义类型,那么IntPair(2,3)
将是该类型的有效文字。
除文字外,用户定义类型的唯一表达式是绑定到该类型值的符号,该类型数组的数组元素以及返回该类型的可调用调用。
数组表达式
数组文字是一个或多个元素表达式的序列,用[
和]
分隔,用分号分隔。 所有元素必须与相同类型兼容。 如果公共元素类型是操作类型或函数类型,则所有元素都必须具有相同的签名,并且在操作的情况下具有相同的受支持的函子。
空阵列文字, []
,是不允许的。 相反,使用new ★[0]
,其中★
作为适当类型的占位符,允许创建所需的长度为零的数组。
给定两个相同类型的数组,可以使用二元+
运算符来形成一个新数组,即两个数组的连接。 例如, [1;2;3] + [4;5;6]
是[1;2;3;4;5;6]
。
数组创建
给定一个类型和一个Int
表达式, new
运算符可用于分配给定大小的新数组。 例如, new Int[i+1]
将分配一个带有i+1
元素的新Int
数组。
新数组的元素被初始化为一个依赖于类型的默认值。 在大多数情况下,这是零的一些变化。
对于对实体的引用的量子比特和可定标,没有合理的默认值。 因此,对于这些类型,缺省值是一个无效的引用,不会导致运行时错误而无法使用。 这与C#或Java等语言中的空引用类似。 包含量子位或可调参数的数组必须使用set
语句填充,然后才能安全使用它们的元素。 数组元素只能在数组声明为可变时设置,例如mutable array = new Int[5]
。 作为参数传递的数组是不可变的。
每种类型的默认值是:
类型 | 默认 |
---|---|
Int | 0 |
Double | 0.0 |
Bool | false |
String | "" |
Qubit | 无效的量子比特 |
Pauli | PauliI |
Result | Zero |
Range | 空的范围, 1..1..0 |
Callable | 无效的可调用 |
Array['T] | 'T[0] |
元组类型是逐元素初始化的。
数组的创建主要是使用初始化可变数组,在[ mutable
] microsoft.quantum.qsharp-ref.type-model.statements#mutable-symbols)语句的右侧。
阵列切片
给定一个数组表达式和一个Range
表达式,一个新的表达式可以使用[
和]
数组slice操作符来形成。 新的表达式将与数组的类型相同,并且将包含由Range
的元素索引的数组项,按照由Range
定义的顺序。 例如,如果a
绑定到一个Double
s数组,则a[3..-1..0]
是一个Double[]
表达式,它包含a的前四个元素,但是以相反的顺序出现在a
。
如果Range
为空,则结果数组切片将为零长度。
如果数组表达式不是一个简单的标识符,则它必须包含在括号中以便分片。 例如,如果a
和b
都是Int
数组,则来自连接的切片将表示为:
(a+b)[1..2..7]
Q#中的所有数组都是从零开始的。 也就是说,数组a
的第一个元素始终a[0]
。
数组元素表达式
给定一个数组表达式和一个Int
表达式,可以使用[
和]
数组元素运算符形成一个新表达式。 新的表达式将与数组的元素类型相同。 例如,如果a
绑定到一个Double
s数组,则a[4]
是一个Double
表达式。
如果数组表达式不是一个简单的标识符,则它必须用圆括号括起来以便选择一个元素。 例如,如果a
和b
都是Int
数组,则来自并置的元素将表示为:
(a+b)[13]
Q#中的所有数组都是从零开始的。 也就是说,数组a
的第一个元素始终a[0]
。
布尔表达式
两个Bool
文字值是true
和false
。
鉴于任何两个表达式与相同的基元类型兼容, ==
和!=
二元运算符可用于构造一个Bool
表达式。 如果两个表达式(不相等),表达式将为真。 对于大小和平等比较,用户定义类型的值在比较之前转换为其基本类型。
Qubit
值的平等比较是身份平等; 也就是说,两个表达式是否确定相同的量子位。 两个量子的状态不会被比较,比较,访问,测量或修改。
由于四舍五入效应, Double
值的平等比较可能会产生误导。 例如, 49.0 * (1.0/49.0) != 1.0
。
给定任意两个数字表达式,二元运算符>
, <
, >=
和<=
可用于构造一个新的布尔表达式,如果第一个表达式分别大于,小于,大于或等于或小于或等于第二个表达式。
给定任何两个布尔表达式, &&
和||
二元运算符可以用来构造一个新的布尔表达式,如果两个表达式中的任何一个或两个都为真,则该布尔表达式为真。
给定任何布尔表达式, !
一元运算符可用于构造一个新的布尔表达式,如果构成表达式为假,则为true。
运算符优先级
除^
以外,所有二元运算符都是右关联的。
用于数组切片和索引的括号[
和]
绑定在任何运算符之前。 操作和函数调用的括号也绑定在任何操作符之前,但在数组索引之后绑定。
运营商按照从高到低的顺序排列:
操作者 | 元数 | 描述 | 操作数类型 |
---|---|---|---|
- , ~~~ | 一元 | 数字负数,逐位补码,逻辑否定(NOT) | Int 或Double 为- , Int 为~~~ , Bool 为! |
^ | 二进制 | 整数功率 | Int |
/ , * , % | 二进制 | 分,乘,整数模 | Int 和Double 为/ 和* , Int 为% |
+ , - | 二进制 | 加法或字符串和数组连接,减法 | Int 或Double ,额外String 或任何数组类型 |
<<< , >>> | 二进制 | 左移,右移 | Int |
< , <= , > , >= | 二进制 | 小于,小于或等于,大于,大于或等于比较 | Int 或Double |
== , != | 二进制 | 相等,不等于比较 | 任何原始类型 |
&&& | 二进制 | 按位与 | Int |
^^^ | 二进制 | 按位XOR | Int |
||| | 二进制 | 按位或 | Int |
&& | 二进制 | 逻辑AND | Bool |
|| | 二进制 | 逻辑或 | Bool |
字符串插值
Q#允许在fail
语句和Log
标准函数中使用字符串。 用于字符串插值的Q#语法是C#7.0语法的子集; Q#不支持逐字(多行)插值字符串。 请参阅C#语法的插值字符串 。