Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Come elaborato in modo più dettagliato nella descrizione del tipo di dati qubit , i calcoli quantistici vengono eseguiti sotto forma di effetti collaterali delle operazioni supportate in modo nativo nel processore quantistico di destinazione. Questi sono, infatti, gli unici effetti collaterali in Q#. Poiché tutti i tipi sono non modificabili, non esistono effetti collaterali che influiscono su un valore rappresentato in modo esplicito in Q#. Di conseguenza, purché un'implementazione di un determinato chiamabile non chiami direttamente o indirettamente alcuna di queste operazioni implementate in modo nativo, l'esecuzione produce sempre lo stesso output, dato lo stesso input.
Q# consente di suddividere in modo esplicito tali calcoli puramente deterministici in funzioni . Poiché il set di istruzioni supportate in modo nativo non è fisso e integrato nel linguaggio stesso, ma piuttosto completamente configurabile ed espresso come libreria di Q#, il determinismo è garantito richiedendo che le funzioni possano chiamare solo altre funzioni e non possano chiamare alcuna operazione. Inoltre, le istruzioni native che non sono deterministiche, ovvero perché influiscono sullo stato quantistico, vengono rappresentate come operazioni. Con queste due restrizioni, le funzioni possono essere valutate non appena il valore di input è noto e, in linea di principio, non è mai necessario valutare più volte per lo stesso input.
Q# quindi distingue tra due tipi di chiamabili: operazioni e funzioni. Tutti i chiamabili accettano un singolo argomento (potenzialmente con valori di tupla) come input e producono un singolo valore (tupla) come output. Sintatticamente, il tipo di operazione viene espresso come <TIn> => <TOut> is <Char>
, dove <TIn>
deve essere sostituito dal tipo di argomento, <TOut>
deve essere sostituito dal tipo restituito e <Char>
deve essere sostituito dalle caratteristiche dell'operazione . Se non è necessario specificare caratteristiche, la sintassi semplifica l'<TIn> => <TOut>
. Analogamente, i tipi di funzione vengono espressi come <TIn> -> <TOut>
.
A parte questa garanzia determinismo, c'è poca differenza tra operazioni e funzioni. Entrambi sono valori di prima classe che possono essere passati liberamente; possono essere usati come valori o argomenti restituiti ad altri chiamabili, come illustrato nell'esempio seguente:
function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit {
return PowImpl(op, pow, _);
}
È possibile creare un'istanza di entrambi in base a una definizione con parametrizzazione di tipo, ad esempio il tipo parametrizzato funzione Pow
in precedenza e possono essere parzialmente applicate come fatto nell'istruzione return
nell'esempio.
Caratteristiche dell'operazione
Oltre alle informazioni sul tipo di input e output, il tipo di operazione contiene informazioni sulle caratteristiche di un'operazione. Queste informazioni, ad esempio, descrivono quali funtori sono supportati dall'operazione. Inoltre, la rappresentazione interna contiene anche informazioni rilevanti per l'ottimizzazione dedotti dal compilatore.
Le caratteristiche di un'operazione sono un set di etichette predefinite e predefinite. Sono espressi sotto forma di espressione speciale che fa parte della firma del tipo. L'espressione è costituita da uno dei set predefiniti di etichette o da una combinazione di espressioni di caratteristiche tramite un operatore binario supportato.
Sono disponibili due set predefiniti, Adj
e Ctl
.
-
Adj
è il set che contiene una singola etichetta che indica che un'operazione è adiacente, ovvero supporta il funtoreAdjoint
e la trasformazione quantistica applicata può essere "annullata", ovvero può essere invertita. -
Ctl
è il set che contiene una singola etichetta che indica che un'operazione è controllabile, ovvero supporta l'functorControlled
e l'esecuzione può essere condizionata sullo stato di altri qubit.
I due operatori supportati come parte delle espressioni di caratteristiche sono l'unione set +
e l'intersezione set *
.
In EBNF (formato Backus-Naur esteso),
predefined = "Adj" | "Ctl";
characteristics = predefined
| "(", characteristics, ")"
| characteristics ("+"|"*") characteristics;
Come ci si aspetterebbe, *
ha una precedenza superiore a +
ed entrambi sono associati a sinistra. Il tipo di un'operazione unitaria, ad esempio, viene espresso come <TIn> => <TOut> is Adj + Ctl
, dove <TIn>
deve essere sostituito con il tipo dell'argomento operazione e <TOut>
sostituito con il tipo del valore restituito.
Nota
L'indicazione delle caratteristiche di un'operazione in questo formato presenta due vantaggi principali; per una, è possibile introdurre nuove etichette senza avere in modo esponenziale molte parole chiave del linguaggio per tutte le combinazioni di etichette. Soprattutto, l'uso di espressioni per indicare le caratteristiche di un'operazione supporta anche le parametriizzazioni rispetto alle caratteristiche dell'operazione in futuro.