Операции и функции
Как подробнее рассказывается в описании типов данных кубит, квантовые вычисления основаны на побочных эффектах операций, которые поддерживает целевой квантовый процессор. По сути, это единственные побочные эффекты в Q#. Так как все типы являются неизменяемыми, невозможно получить побочные эффекты, влияющие на явным образом представленное в Q# значение. Поэтому если реализация определенных вызываемых объектов не вызывает прямо или косвенно какие-либо из таких собственных операций, при ее выполнении всегда будут возвращаться одинаковые входные данные (при одинаковых входных).
Q# позволяет явным образом разбить такие детерминированные вычисления на функции. Так как набор собственных поддерживаемых инструкций не является строго фиксированным и встроенным в язык программирования, а настраивается для каждой системы отдельно в формате библиотеки Q#, детерминизм можно гарантировать только при том условии, что функция будет вызывать только другие функции, но не будет вызывать операции. Кроме того, собственные инструкции, не являющиеся детерминированными в силу своей квантовой природы, должны быть выражены как операции. При соблюдении этих двух ограничений функции могут вычислить результат сразу, когда будут известны входные значения, и их никогда не потребуется вычислять более одного раза для тех же входных данных.
По этим причинам Q# четко разделяет два типа вызываемых объектов: операции и функции. Все вызываемые объекты принимают в качестве входных данных единственный аргумент (который может содержать кортеж) и возвращают единственное значение (кортеж). Синтаксис для типа операций выражается как <TIn> => <TOut> is <Char>
, где <TIn>
нужно заменить типом аргумента, <TOut>
— типом возвращаемого значения, а <Char>
— характеристиками операции. Если характеристики операции указывать не нужно, используется упрощенный синтаксис: <TIn> => <TOut>
. Аналогичным образом, типы функций выражаются так: <TIn> -> <TOut>
.
Операции мало чем отличаются от функций, кроме описанного выше механизма гарантии детерминизма. И те, и другие являются значениями первого класса, которые можно свободно передавать в программах. И те, и другие можно использовать как возвращаемые значения или аргументы для других вызываемых объектов, как показано в примере ниже:
function Pow<'T>(op : 'T => Unit, pow : Int) : 'T => Unit {
return PowImpl(op, pow, _);
}
И те, и другие позволяют создавать экземпляры на основе параметризованного определения, как например представленная выше функция Pow
с параметризацией типа. И те, и другие можно применять частично, как в операторе return
в примере.
Характеристики операций
В дополнение к информации о входных и выходных типах, тип операции содержит информацию о характеристиках этой операции. В частности, она определяет, какие функторы поддерживает эта операция. Кроме того, внутреннее представление содержит сведения для оптимизации, которые выводятся компилятором.
Характеристики операции задаются как набор предустановленных и (или) встроенных меток. Они выражаются в формате специальных выражений, входящих в состав сигнатуры типа. Такие выражения могут состоять из одного предустановленного набора меток или из некоторого сочетания характеристик, выраженных через поддерживаемый двоичный оператор.
Существуют два предопределенных набора: Adj
и Ctl
.
- Набор
Adj
содержит одну метку, которая обозначает сопрягаемость операции, то есть поддержку функтораAdjoint
и возможность "отменить" (то есть инвертировать) примененное квантовое преобразование. - Набор
Ctl
содержит одну метку, которая обозначает контролируемость операции, то есть поддержку функтораControlled
и возможность управлять ее выполнением через состояние других кубит.
В составе выражений характеристик поддерживаются два оператора: объединение наборов +
и пересечение наборов *
.
В EBNF,
predefined = "Adj" | "Ctl";
characteristics = predefined
| "(", characteristics, ")"
| characteristics ("+"|"*") characteristics;
как и следует ожидать, *
имеет более высокий приоритет, чем +
, и оба они имеют левую ассоциативность. Тип унитарной операции выражается, например, в виде <TIn> => <TOut> is Adj + Ctl
, где <TIn>
следует заменить типом аргумента операции, а <TOut>
— типом возвращаемого значения.
Примечание
Указание характеристик операции в таком формате имеет два важных преимущества. Во-первых, можно добавлять новые метки без экспоненциального роста количества ключевых слов языка, позволяющих выразить любое сочетание меток. И что еще важнее, использование выражений для обозначения характеристик операции позволит в будущем предоставить поддержку параметризации для характеристик операций.