共用方式為


類型參數化

Q# 支援類型參數化作業和函式。 Q# 標準連結庫會大量使用類型參數化可呼叫專案,以提供許多有用的抽象概念,包括函式,例如 MappedFold,這些函式是函式語言中熟悉的。

若要激勵型別參數化的概念,請考慮函式 Mapped範例,此範例會將指定的函式套用至數位中的每個值,並傳回具有計算值的新陣列。 您可以完全描述這項功能,而不需指定輸入和輸出陣列的項目類型。 由於確切的類型不會變更函式的實作 Mapped,因此應該可以針對任意專案類型定義此實作:我們想要定義 處理站範本,指定輸入和輸出陣列中專案的具體類型,會傳回對應的函式實作。 這個概念是以型別參數的形式正規化。

具體化

任何作業或函式宣告都可以指定一或多個型別參數,這些參數可用來做為可呼叫者輸入或輸出的類型或部分類型,或兩者。 例外狀況是進入點,必須具象,而且無法進行類型參數化。 類型參數名稱開頭為刻度 ('),而且可能會在輸入和輸出類型中出現多次。 對應至可呼叫簽章中相同類型參數的所有自變數都必須是相同的類型。

類型參數化可呼叫對象必須進行具體化,也就是說,必須先提供必要的類型自變數,才能將它指派或傳遞為自變數,讓所有類型參數都可以取代為具體類型。 如果類型是其中一個內建類型、struct 類型,或它是目前範圍內的具體類型,則類型會被視為具象。 下列範例說明類型在目前範圍內具象的意義,並在下面更詳細地說明:

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

        mutable mapped = new 'T2[Length(array)];
        for (i in IndexRange(array)) {
            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, 'TIn) => Unit 的新作業,前提是傳統位 (類型為 Bool) 設定為 true;這通常稱為傳統控制的 op版本。

函式 Mapped 接受任意專案類型的數位 'T1 作為自變數、將指定的 mapper 函式套用至每個專案,並傳回包含對應專案之類型的新數位列 'T2[]。 它定義於 Microsoft.Quantum.Array 命名空間中。 基於此範例的目的,會編號類型參數,以避免讓這兩個函式中的型別參數具有相同名稱,讓討論更加令人困惑。 這並非必要;不同可呼叫物件的類型參數可能具有相同的名稱,且所選的名稱只會在該可呼叫的定義內顯示且相關。

函式 AllCControlled 接受作業陣列,並傳回包含這些作業傳統控制版本的新陣列。 Mapped 的呼叫會將其類型參數 'T1 解析為 'T3 => Unit,並將其類型參數 'T2 解析為 (Bool,'T3) => Unit。 解析型別自變數是由編譯程式根據指定自變數的類型來推斷。 我們說它們 隱含 由呼叫表達式的 自變數所定義。 您也可以明確指定類型自變數,就像在同一行中 CControlled 所做的一樣。 無法推斷型別自變數時,需要明確具體化 CControlled<'T3>

類型 'T3AllCControlled的內容中是具體的,因為它以 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 是目前呼叫的類型參數。 具體地說,假設使用 作業 H 叫用 Foo,以及類型為 Qubit的自變數 argFoo 接著使用類型自變數 (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);
   }

為了簡單起見,會強制執行更嚴格的需求。 請注意,對於包含至少一個具象可呼叫的迴圈,而沒有任何類型參數,這類可呼叫者可確保該迴圈內的類型參數化可呼叫物件一律會使用固定的類型自變數集來呼叫。