Share via


呼び出し可能宣言

グローバル スコープで宣言された 呼び出し可能な宣言 (呼び出し可能) は、既定でパブリックに表示されます。つまり、同じプロジェクト内および宣言されているアセンブリを参照するプロジェクト内の任意の場所で使用できます。 アクセス修飾子を使用すると、特定のライブラリに依存するコードを壊さずに後で実装の詳細を変更できるよう、可視性を現在のアセンブリにのみ制限できます。

Q# では、演算と関数の 2 種類の callable がサポートされています。 トピック「演算と関数」で、この 2 つの違いについて詳しく説明しています。 Q# では、"テンプレート" の定義もサポートされています。たとえば、特定の callable 用の型パラメーター化された実装などです。 詳細については、「 型パラメーター化」を参照してください。

Note

このような型パラメーター化された実装では、型引数の特定のプロパティに依存する言語コンストラクトを使用することはできません。現在、 Q# で型制約を表現したり、特定の型引数に対して特殊な実装を定義したりする方法はありません。

callable とファンクタ

Q# では、特定の目的に特化した実装が可能です。たとえば、 Q# の演算では、特定の "ファンクタ" のサポートを暗黙的または明示的に定義できます。また、特定のファンクタが callable に適用された場合に呼び出す特殊な実装も定義できます。

ファンクタは、ある意味で、それが適用された callable との特定の関係を持つ新しい callable の実装を定義するファクトリです。 ファンクタは、適用された callable の実装の詳細へのアクセスを要求するるという点で、従来の上位レベルの関数より優れています。 その意味では、テンプレートなど、他のファクトリに似ています。 これらは、型パラメーター化された呼び出し可能な呼び出し可能にも適用できます。

次の操作 ApplyQFTを検討してください。

    operation ApplyQFT(qs : Qubit[]) : Unit is Adj + Ctl {
        let length = Length(qs);
        Fact(length >= 1, "ApplyQFT: Length(qs) must be at least 1.");
        for i in length - 1..-1..0 {
            H(qs[i]);
            for j in 0..i - 1 {
                Controlled R1Frac([qs[i]], (1, j + 1, qs[i - j - 1]));
            }
        }
    }

この操作は 型 Qubit[] の引数を受け取り、 型の値を返します UnitApplyQFT の宣言内の注釈 is Adj + Ctl は、この演算が AdjointControlled の両方のファンクタをサポートしていることを示しています。 (詳細については、「演算の特性」を参照してください)。 式Adjoint ApplyQFTは、 のアジョネットを実装する特殊化にアクセスし、 Controlled ApplyQFTApplyQFT制御されたバージョンApplyQFTを実装する特殊化にアクセスします。 元の操作の引数に加えて、制御されたバージョンの操作は制御量子ビットの配列を受け取り、これらの制御量子ビットがすべて |1⟩ 状態であることを条件に元の操作を適用します。

理論的には、隣接バージョンを定義できる演算には、制御されたバージョンも必要であり、その逆も同様です。 ただし、実際には、一方または他の実装を開発するのは難しい場合があります。特に、成功までの繰り返しパターンに従った確率的な実装の場合です。 このため、 Q# を使用すると、各ファンクタのサポートを個別に宣言できます。 ただし、2 つのファンクタは可換であるため、両方のサポートを定義する演算では、両方のファンクタがその演算に適用される場合の実装 (通常は暗黙的に定義され、コンパイラによって生成される) も必要です。

関数に適用できるファンクターはありません。 現在、関数には 1 つの本体実装があり、それ以上の特殊化はありません。 たとえば、宣言

    function Hello (name : String) : String {
        $"Hello, {name}!"
    }

上記の式は、次の式と同じです。

    function Hello (name : String) : String {
        body ... {
            $"Hello, {name}!"
        }
    }

ここでは、 body は、指定された実装が関数 Hello の既定の本体に適用されることを指定しています。つまり、呼び出しの前にファンクタや他のファクトリ メカニズムが適用されていない場合に、実装が呼び出されます。 body ... の 3 つのドットは、関数宣言内の引数項目をコピーしてこの場所に貼り付けるべきであることを示すコンパイラ ディレクティブに対応しています。

親呼び出し可能宣言の引数をコピーして貼り付ける場所を明示的に示す理由は、1 つは引数宣言を繰り返す必要はありません。2 つは、ファンクターなどの Controlled 追加の引数を必要とするファンクターを一貫した方法で導入できるようにするためです。

既定の本文の実装を定義する特殊化が 1 つだけある場合は、フォーム body ... { <implementation> } の追加の折り返しを省略できます。

再帰

Q# callable は、直接または間接的に、再帰的に実行できます。また、任意の順序で宣言できます。演算または関数がそれ自体を呼び出す場合や、呼び出し元を直接または間接的に呼び出す別の callable を呼び出す場合があります。

量子ハードウェアで実行する場合、スタック領域が制限され、そのスタック領域の制限を超える再帰によってランタイム エラーが発生する可能性があります。