형식 매개 변수화

Q#은 형식 매개 변수화된 연산 및 함수를 지원합니다. Q# 표준 라이브러리는 함수형 언어에서 익숙한 MappedFold와 같은 함수를 포함하여 유용한 추상화 호스트를 제공하기 위해 매개 변수화된 호출 가능 항목 형식을 많이 사용합니다.

형식 매개 변수화의 개념에 동기를 부여하려면 지정된 함수를 배열의 각 값에 적용하고 계산된 값과 함께 새 배열을 반환하는 함수 Mapped의 예를 고려합니다. 이 기능은 입출력 배열의 항목 종류를 지정하지 않고도 완벽하게 설명할 수 있습니다. 정확한 형식은 Mapped 함수의 구현을 변경하지 않으므로 임의의 항목 종류에 대해 이 구현을 정의할 수 있어야 합니다. 입출력 배열의 항목에 대한 구체적인 형식을 지정하면 해당 함수 구현이 반환되는 팩터리 또는 템플릿을 정의하려고 합니다. 이 개념은 형식 매개 변수의 형식으로 공식화됩니다.

구체화

모든 연산 또는 함수 선언은 호출 가능 입력, 출력 또는 입출력 형식의 일부 또는 형식으로 사용할 수 있는 하나 이상의 형식 매개 변수를 지정할 수 있습니다. 예외는 구체적이어야 하고 형식 매개 변수화될 수 없는 진입점입니다. 형식 매개 변수 이름은 틱(')으로 시작하며 입출력 형식에 여러 번 나타날 수 있습니다. 호출 가능한 서명의 동일한 형식 매개 변수에 해당하는 모든 인수는 동일한 형식이어야 합니다.

형식 매개 변수화된 호출 가능 항목은 구체화되어야 합니다. 즉, 인수로 할당하거나 전달하려면 필요한 형식 인수를 제공해야 합니다. 따라서 모든 형식 매개 변수를 구체적인 형식으로 바꿀 수 있습니다. 형식은 기본 제공 형식 또는 사용자 정의 형식 중 하나이거나 현재 범위 내에서 구체적인 경우 구체적인 것으로 간주됩니다. 다음 예는 형식이 현재 범위 내에서 구체적이라는 것이 무엇을 의미하는지 보여 주며 아래에 더 자세히 설명되어 있습니다.

    function Mapped<'T1, 'T2> (
        mapper : 'T1 -> 'T2,
        array : 'T1[]
    ) : 'T2[] {

        mutable mapped = new 'T2[Length(array)];
        for (i in IndexRange(array)) {
            set mapped w/= i <- mapper(array[i]);
        }
        return mapped;
    }

    function AllCControlled<'T3> (
        ops : ('T3 => Unit)[]
    ) : ((Bool,'T3) => Unit)[] {

        return Mapped(CControlled<'T3>, ops); 
    }

CControlled 함수는 Microsoft.Quantum.Canon 네임스페이스에 정의되어 있습니다. 'TIn => Unit 형식의 연산 op를 인수로 사용하고 클래식 비트(형식 Bool)가 true로 설정된 경우 원래 연산을 적용하는 (Bool, 'TIn) => Unit 형식의 새 연산을 반환합니다. 이는 일반적으로 op의 클래식 제어 버전이라고 합니다.

Mapped 함수는 임의의 항목 종류 'T1의 배열을 인수로 취하고 지정된 mapper 함수를 각 항목에 적용하고 매핑된 항목을 포함하는 'T2[] 형식의 새 배열을 반환합니다. Microsoft.Quantum.Array 네임스페이스에 정의되어 있습니다. 예제의 목적을 위해 두 함수의 형식 매개 변수에 동일한 이름을 지정하여 논의를 더 혼란스럽게 하지 않도록 형식 매개 변수에 번호가 지정되었습니다. 이 작업은 필요하지 않습니다. 다른 호출 가능 항목에 대한 형식 매개 변수는 동일한 이름을 가질 수 있으며 선택한 이름은 해당 호출 가능 항목의 정의 내에서만 볼 수 있고 관련이 있습니다.

AllCControlled 함수는 연산 배열을 사용하여 이러한 연산의 클래식 제어 버전을 포함하는 새 배열을 반환합니다. Mapped의 호출은 형식 매개 변수 'T1'T3 => Unit로, 형식 매개 변수 'T2(Bool,'T3) => Unit로 확인합니다. 확인 형식 인수는 지정된 인수의 형식을 기반으로 컴파일러에서 유추됩니다. 호출 식의 인수에 의해 암시적으로 정의된다고 합니다. 같은 줄의 CControlled에 대해 수행되는 것처럼 형식 인수를 명시적으로 지정할 수도 있습니다. 형식 인수를 유추할 수 없는 경우 명시적 구체화 CControlled<'T3>이 필요합니다.

'T3 형식은 AllCControlled의 각 호출에 대해 알려져 있으므로 AllCControlled의 컨텍스트 내에서 구체적입니다. 즉, 형식 매개 변수화할 수 없는 프로그램의 진입점을 알게 되면 AllCControlled에 대한 각 호출에 대한 구체적인 형식 'T3도 알게 되어 특정 형식 확인에 적합한 구현이 다음과 같이 생성될 수 있습니다. 프로그램에 대한 진입점이 알려지면 컴파일 시간에 모든 형식 매개 변수 사용을 제거할 수 있습니다. 이 프로세스를 단형화라고 합니다.

런타임에만 수행되는 것이 아니라 컴파일 시간에 실제로 수행될 수 있도록 하려면 몇 가지 제한이 필요합니다.

제한

다음 예제를 참조하세요.

    operation Foo<'TArg> (
        op : 'TArg => Unit,
        arg : 'TArg
    ) : Unit {

        let cbit = RandomInt(2) == 0;
        Foo(CControlled(op), (cbit, arg));        
    } 

Foo는 호출 시 무한 루프가 발생한다는 점을 무시하면, 설명이라는 목적에 부합합니다. Foo는 전달된 원래 연산 op의 클래식 제어 버전과 원래 인수 외에 임의의 클래식 비트를 포함하는 튜플을 사용하여 자신을 호출합니다.

재귀의 각 반복에 대해 다음 호출의 형식 매개 변수 'TArg(Bool, 'TArg)로 확인됩니다. 여기서 'TArg는 현재 호출의 형식 매개 변수입니다. 구체적으로 FooH 연산과 Qubit 형식의 인수 arg로 호출되었다고 가정합니다. 그런 다음 Foo는 형식 인수 (Bool, Qubit)를 사용하여 자체를 호출한 다음 (Bool, (Bool, Qubit)) 형식 인수를 사용하여 Foo를 호출합니다. 분명히 이 경우 Foo는 컴파일 타임에 단일화될 수 없습니다.

형식 매개 변수화된 호출 가능 항목만 포함하는 호출 그래프의 주기에는 추가 제한 사항이 적용됩니다. 각 호출 가능 항목은 순환을 통과한 후 동일한 형식 인수 집합으로 호출해야 합니다.

참고

덜 제한적일 수 있으며 다음 함수와 같이 주기의 각 호출 가능 항목에 대한 유한한 주기를 요구할 수 있습니다. 이 주기가 끝나면 원래 형식 인수 세트를 사용하여 이 함수가 호출됩니다.

   function Bar<'T1,'T2,'T3>(a1:'T1, a2:'T2, a3:'T3) : Unit{
       Bar<'T2,'T3,'T1>(a2, a3, a1);
   }

단순화를 위해 더 제한적인 요구 사항이 적용됩니다. 형식 매개 변수 없이 하나 이상의 구체적인 호출 가능 항목을 포함하는 주기의 경우 이러한 호출 가능 항목은 해당 주기 내의 형식 매개 변수화된 호출 가능 항목이 항상 고정 형식 인수 세트로 호출되도록 합니다.