操作と関数
量子ビット データ型の説明でさらに詳細に補足説明されているように、量子計算は、対象となる量子プロセッサでネイティブにサポートされている演算の副次的作用の形式で実行されます。 これらは実際には、Q# での唯一の副次的作用です。 すべての型が不変であるため、Q# で明示的に表される値に影響を与える副次的作用はありません。 そのため、特定の callable の実装により、これらのネイティブに実装されている演算が直接または間接的に呼び出されない限り、同じ入力である場合は、その実行によって常に同じ出力が生成されます。
Q# では、このような純粋に決定論的な計算を "関数" に明示的に分割できます。 ネイティブにサポートされている一連の命令は固定され、言語自体に組み込まれているわけではなく、完全に構成可能で Q# ライブラリとして表されるため、関数が他の関数のみを呼び出し、操作を呼び出せないことを要求することで、決定性は保証されます。 さらに、量子状態に影響を与えるなどの理由で決定論的ではないネイティブ命令は、演算として表されます。 これらの 2 つの制限により、関数はその入力値がわかるとすぐに評価でき、原則として、同じ入力に対して複数回評価を行う必要はありません。
そのため、Q# では、演算と関数という 2 種類の callable を区別します。 すべての callable は、入力として 1 つの引数 (タプル値である可能性がある) を受け取り、出力として 1 つの値 (タプル) を生成します。 構文的に、演算の型は <TIn> => <TOut> is <Char>
として表されます。ここで、<TIn>
は引数の型に置き換えられ、<TOut>
は戻り値の型に置き換えられ、<Char>
は演算の特性に置き換えられます。 特性を指定する必要がない場合は、構文が <TIn> => <TOut>
に簡略化されます。 同様に、関数の型は <TIn> -> <TOut>
として表されます。
この決定性の保証を除き、演算と関数に違いはほとんどありません。 どちらも、自由に渡すことができるファースト クラス値であり、次の例に示されているように、他の callable への戻り値または引数として使用できます。
function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit {
return PowImpl(op, pow, _);
}
どちらも、前の型パラメーター化された関数 Pow
などの型パラメーター化された定義に基づいてインスタンス化でき、例の return
ステートメントで行われたように部分適用できます。
演算の特性
演算の型には、入出力の型に関する情報に加えて、演算の特性に関する情報が含まれています。 この情報には、たとえば、その演算ではどのようなファンクターがサポートされているかが記述されています。 さらに、内部表現には、コンパイラによって推論される最適化に関連した情報も含まれています。
演算の特性は、一連の定義済みの組み込みラベルです。 これらは、型シグネチャの一部である特殊な式の形式で表されます。 この式は、ラベルの定義済みのセットのいずれかか、またはサポートされている 2 項演算子を使用した特性の式の組み合わせで構成されます。
定義済みのセットには、Adj
と Ctl
の 2 つがあります。
-
Adj
は、演算が随伴可能であることを示す 1 つのラベルが含まれているセットです。つまり、これはAdjoint
ファンクターをサポートしており、適用された量子変換を "元に戻す" (反転させる) ことができます。 -
Ctl
は、演算が制御可能であることを示す 1 つのラベルが含まれているセットです。つまり、これはControlled
ファンクターをサポートしており、その実行を他の量子ビットの状態に対して条件付けることができます。
特性の式の一部としてサポートされている 2 つの演算子は、和集合 +
と積集合 *
です。
EBNF では、次のようになります。
predefined = "Adj" | "Ctl";
characteristics = predefined
| "(", characteristics, ")"
| characteristics ("+"|"*") characteristics;
予測されるように、*
は +
より優先順位が高く、どちらも左結合です。 たとえば、ユニタリ演算の型は <TIn> => <TOut> is Adj + Ctl
として表されます。ここで、<TIn>
は演算の引数の型に、<TOut>
は返される値の型に置き換える必要があります。
Note
この形式で演算の特性を示すことの主な利点として、次の 2 つがあります。その 1 つは、ラベルのすべての組み合わせに対して指数関数的に増える言語キーワードを使用しなくても新しいラベルを導入できることです。 おそらく、さらに重要なのは、式を使用して演算の特性を示すことにより、将来、演算の特性でパラメーター化もサポートできるようになる点です。