Q#の呼び出しの学習

Q#言語の呼び出しステートメントについて、ドキュメント読み進めて理解を深めたいと思います。

# 参考
- [呼び出しステートメント](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/statements/callstatements#call-statements)
- [特殊化宣言](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/programstructure/specializationdeclarations)
- [呼び出し可能宣言](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/programstructure/callabledeclarations)
- [関数と演算](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/typesystem/operationsandfunctions#operations-and-functions)
- [Q# Language and Core Libraries Design](https://github.com/microsoft/qsharp-language)

# 呼び出し可能宣言

Q#言語では、```操作```と```関数```の2つが存在します。
それぞれは以下のように宣言することができます。

```Q#
namespace <project name> {

    /// # 関数
    function <name>(<args>) : <return type> {
        ...
    }

    /// # 操作
    operation <name>(<args>) : <return type> {
        ...
    }

}
```

以後、oeprationの宣言を```操作```とし、functionの宣言を```関数```と呼びます。

また、```操作```、```関数```の引数```args```の定義には型が必要ですが、
後述する```lambda```には型宣言は不要になります。

具体例は以下になります。
```Q#
namespace Sample {

    /// # 関数
    function Fop(x: Double) : Unit {
        ...
    }

    /// # 操作
    operation Op(x:Int, y:Int) : Unit {
        ...
    }

    /// # 関数を受け取る関数
    function Callback (toStr:Int -> String) : Unit {
        ...
        Message(toStr(5));
    }
    function Callback2 (type: Int, toStr: (Int, String) -> String) : Unit {
        ...
        Message(toStr(type, "str"));
    }
}

}
```

## Lambda

```関数```や```操作```の引数が多く一部をバインドしたい時やそんなに大きくない```関数```や```操作```を一時的に定義したい場合があると思います。

そんな時は、Lambdaがあなたのコードを優しく包み込んでくれます。ｗ

```Q#
/// 無名関数
<args> -> <return value>

/// 無名操作
<args> => <return value>
```

上記のように```->```や```=>```を利用し定義します。
具体的な例は以下のようになります。
```Q#
    operation Op () : Unit {

        /// 例１
        let a = x => Message($"{x}");
        a(3);

        let v = 10;
        /// 例２　引数が複数の場合は()で囲む
        let b = (x, y) -> Message($"{v} {x} {y}");
        b(1, 2);
    }
```
例１は、引数が単体の場合の```lambda```になります。
例２は、引数が複数の場合の```lambda```になります。
それだけではなく、```lambda```の範囲のスコープで定義されている変数などをキャプチャし利用することも可能です。実際に変数```v```がキャプチャされています。

そのほかの例を見たい方は[こちら](https://devblogs.microsoft.com/qsharp/introducing-q-lambda-expressions/)

公式では以下のような事が記載されています。[詳細](https://docs.microsoft.com/ja-jp/azure/quantum/user-guide/language/typesystem/operationsandfunctions)

>特性を指定する必要がない場合は、構文が <TIn> => <TOut> に簡略化されます。 同様に、関数の型は <TIn> -> <TOut> として表されます。
>この決定性の保証を除き、演算と関数に違いはほとんどありません。

```演算```と記載されているところは```操作```として読み替えていただくと幸いです。
```特性```とは、後述するファンクタのラベルだと思ってください。

「```=>```も```->```違いはないですよ」という事を言いたいのでしょうが、

以下の例を見てください。
```関数```を受け取る```関数```に```操作```を渡すとエラーになります。
```Q#
    @EntryPoint()
    function Main() : Unit {
        /// 関数に関数を渡す。
        Callback(1, x -> $"{x}");
        /// 関数に操作を渡す。
        Callback(2, x => $"{x}");　// error QS0001
    }

    /// 関数(->)を受け取る関数
    function Callback (x: Int, toStr: Int -> String) : Unit {
        Message(toStr(x));
    }
```

つまり、明確な違いがあるようです。ｗ
それとも、自分が公式から読み取った理解が悪いのかな。

## ファンクタ

Q#言語では、```Adjoint```と```Controlled```の２つのファンクタがサポートされているみたいです。
が、これらは全て```操作```に対しての物になります。

公式には、以下のように文言があります。
> 関数に適用できるファンクタはありません。そのため、関数には現在 1 つの本体実装しかなく、それ以上の特殊化はありません。 

そして、この```操作```というのは量子演算の最適化などに影響がある為
今回は軽く触れる程度にします。

| ファンクタ | 内容 |
| --- | --- |
|　Adjoint |適用された量子変換を "元に戻す" (反転させる) ことができます。 |
| Controlled |その実行を他の量子ビットの状態に対して条件付けることができます。 |

上記のファンクターは２種類の方法で宣言することが可能です。

### ```ラベル```での宣言方法

```Adjoint```は、```Adj```で、```Controlled```は、```Ctl```になります。
ラベルの宣言の式は一部サポートされているらしく、```+```と```*```の対応がされています。

```Q#
    operation <name>(<Args>) : <Return Type> is Adj {...}
    operation <name>(<Args>) : <Return Type> is Ctl {...}
　　/// ファンクターの和集合
    operation <name>(<Args>) : <Return Type> is Adj + Ctl {...}
    /// ファンクターの積集合
    operation <name>(<Args>) : <Return Type> is Adj * Ctl {...}
```

### ```ディレクティブ```での宣言方法

こちらは、```操作```内で宣言します。
各ファクタ毎にディレクティブが存在します。

```Q#
    operation <name>(<Args>) : <Return Type>{
        body (...) {  }
        /// auto、 self、invert のいずれかを指定することが可能
        adjoint <auto|self|invert>;
        /// auto、 distribute のいずれかを指定することが可能
        controlled <auto|distribute>;
        /// auto、self、invert、distributeのいずれかを指定することが可能
        controlled adjoint <auto|self|invert|distribute>;
    }
```

上記の方法は、コンパイラによって自動的に生成するための宣言になります。
また、```body```は```操作```または```関数```の処理本体になるので自動生成の宣言はありません。
その為、```(...)```で全ての引数をキャプチャし```{``` ```}```内で使用すること明示します。

自動生成宣言をしない場合の例は以下のような感じなります。
もっと例が見たい方は[こちら](https://github.com/microsoft/qsharp-language/blob/main/Implemented/partial-specialization-inference.md)

```Q#
    operation Unitary () : Unit {
        body (...) {
            Message ("invocation of 'Unitary'"); 
        }

        adjoint (...) {
            Message ("invocation of 'Adjoint Unitary'"); 
        }

        controlled (cs, ...) {
            Message ("invocation of 'Controlled Unitary'"); 
        }

        controlled adjoint (cs, ...) {
            Message ("invocation of 'Controlled Adjoint Unitary'"); 
        }
    }
```

これらの```ディレクティブ```が１つだけのみである場合、つまり```adjoin```や```controlled```や```controlled adjoint```などが宣言されていない場合は、```body```として省略されます。

その為、以下のような宣言は、
```Q#
    operation Op (x: Int) : Unit {
        body (...) {
             Message ($"{x}");
        }
    }
```
以下のように宣言できます。
```Q#
    operation Op (x: Int) : Unit {
        Message ($"{x}");
    }
```

上記の宣言は、```関数```も同じです。

# 型パラメーター化

これは他の言語にもあるように、ジェネリックプログラミングやテンプレートなどの事です。
Q#言語では、以下のように宣言することで関数を抽象化することができます。

```関数```、```操作```の引数、戻り値あるいはそれらの一部分を抽象化することが可能です。

先ほどから抽象化と言っていますが、ここでは```抽象化＝型パラメーター化```だと思ってください。

```関数```、```操作```の定義名の後に```<>```で囲い
```'```（ティック）から始まる型名が、抽象化に当たります。

```Q#
    function <name><'T> (<argument>:'T): Unit {...} 

    operation <name><'IT, 'OT> (<argument>: 'IT, <argument2>: 'IT): 'OT {...} 
```

以下に具体例を記載します。

```Q#
    @EntryPoint()
    operation Main() : Unit {
        F(1, 0.10);                               //1 0.1
        F(2, "moji");                             //2 moji
        F(3, 1);                                  //3 1
        let d = O(4, 0.05, x -> Message($"{x}")); //4
        let _ = O(5, (), x -> Message($"{x}"));   //5
    }

    function F<'T> (x: Int, y: 'T): Unit {
        Message($"{x} {y}");
    }

    operation O<'IT, 'OT> (x: 'IT, y: 'OT, Opt: 'IT -> Unit) : 'OT {
        Opt(x);
        return y;
    }
```

以上です。

# 所感

値リテラル・制御文・関数などを行ってきたのでそろそろ
Q#を利用して量子プログラミングまで行けそうかなと思うのですが、

あ、ファイル分割等もやらないといけないかもだけど特に難しくなく直感的にできるので何とも言えない。

他に必要な事前知識あるのかな。。。量子なんて知らんわ！