호출 가능한 선언

전역 scope 선언된 호출 가능한 선언 또는 호출 가능 선언은 기본적으로 공개적으로 표시됩니다. 즉, 동일한 프로젝트의 모든 위치와 선언된 어셈블리를 참조하는 프로젝트에서 사용할 수 있습니다. 액세스 한정자를 사용하면 특정 라이브러리에 의존하는 코드를 중단하지 않고 나중에 구현 세부 정보를 변경할 수 있도록 현재 어셈블리에 대한 표시 유형을 제한할 수 있습니다.

Q#은 연산과 함수의 두 가지 호출 가능 항목을 지원합니다. 연산 및 함수 항목에서는 둘의 차이점에 대해 자세히 설명합니다. 또한 Q#은 템플릿 정의를 지원합니다. 예를 들어, 특정 호출 가능 항목에 대한 형식 매개 변수를 구현합니다. 자세한 내용은 형식 매개 변수화를 참조하세요.

참고

이러한 형식 매개 변수화 구현은 형식 인수의 특정 속성에 의존하는 언어 구문을 사용할 수 없습니다. 현재 Q#에서 형식 제약 조건을 표현하거나 특정 형식 인수에 대한 특수 구현을 정의하는 방법이 없습니다.

호출 가능 항목과 펀터

Q#은 특정 목적을 위한 특수 구현을 허용합니다. 예를 들어, Q#의 연산은 특정 펀터에 대한 지원을 암시적 또는 명시적으로 정의할 수 있으며 이와 함께 특정 함수가 해당 호출 가능 항목에 적용될 때 호출할 특수 구현을 정의할 수 있습니다.

어떤 의미에서 펀터는 그것이 적용된 호출 가능 항목과 특정한 관계가 있는 새로운 호출 가능 항목 구현을 정의하는 팩터리입니다. 펀터는 적용된 호출 가능 항목의 구현 세부 정보에 액세스해야 한다는 점에서 기존의 상위 수준 함수보다 많습니다. 그런 의미에서 템플릿과 같은 다른 팩토리와 유사합니다. 형식 매개 변수가 있는 호출 가능 개체에도 적용할 수 있습니다.

다음 작업을 고려합니다. 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[]Unit의 값을 반환합니다. ApplyQFT 선언의 주석 is Adj + Ctl은 연산이 AdjointControlled 펀터를 모두 지원함을 나타냅니다. (자세한 내용은 연산 특성 참조). 식 Adjoint ApplyQFT 은 의 부속 ApplyQFT을 구현하는 특수화에 액세스하고 Controlled ApplyQFT 제어된 버전의 ApplyQFT를 구현하는 특수화에 액세스합니다. 원래 작업의 인수 외에도 제어된 버전의 작업은 제어 큐비트 배열을 사용하고 이러한 모든 컨트롤 큐비트가 |1⟩ 상태에 있는 조건에 원래 작업을 적용합니다.

이론적으로, 수반 행렬 버전을 정의할 수 있는 연산에는 제어 버전도 있어야 하며 그 반대의 경우도 마찬가지입니다. 그러나 실제로는 특히 성공할 때까지 반복 패턴을 따르는 확률적 구현의 경우 둘 중 하나에 대한 구현을 개발하기 어려울 수 있습니다. 이러한 이유로 Q#을 사용하면 각 펀터에 대한 지원을 개별적으로 선언할 수 있습니다. 그러나 두 펀터가 왕복 이동하기 때문에 두 펀터 모두에 대한 지원을 정의하는 연산에는 두 펀터가 모두 연산에 적용될 때의 구현(일반적으로 암시적으로 정의됨, 즉 컴파일러 생성)도 있어야 합니다.

함수에 적용할 수 있는 펀터가 없습니다. 함수에는 현재 정확히 하나의 본문 구현이 있으며 더 이상 전문화가 없습니다. 예를 들어, 선언

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

위의 식은 아래의 식과 동일합니다.

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

여기에서 body는 지정된 구현이 Hello 함수의 기본 본문에 적용되도록 지정합니다. 즉, 호출 전에 펀터 또는 기타 팩터리 메커니즘이 적용되지 않은 경우 구현이 호출됩니다. body ...에 있는 세 개의 점은 함수 선언의 인수 항목을 복사하여 이 지점에 붙여넣어야 함을 나타내는 컴파일러 지시문에 해당합니다.

부모 호출 가능 선언의 인수를 복사하여 붙여넣을 위치를 명시적으로 나타내는 이유는 두 가지입니다. 하나는 인수 선언을 반복할 필요가 없으며, 두 가지는 functor와 같은 Controlled 추가 인수가 필요한 functor를 일관된 방식으로 도입할 수 있도록 합니다.

기본 본문의 구현을 정의하는 특수화가 정확히 하나 있는 경우 양식 body ... { <implementation> } 의 추가 래핑을 생략할 수 있습니다.

재귀

Q# 호출 가능 항목은 직간접적으로 재귀적일 수 있으며 임의의 순서로 선언될 수 있습니다. 연산이나 함수는 자신을 호출하거나 호출자를 직접 또는 간접적으로 호출하는 다른 호출자를 호출할 수 있습니다.

양자 하드웨어에서 실행할 때 스택 공간이 제한될 수 있으며, 해당 스택 공간 제한을 초과하는 재귀는 런타임 오류를 발생시킵니다.