ВведениеIntroduction

ОбзорOverview

Microsoft Power Query предоставляет эффективный интерфейс получения данных, обладающий множеством возможностей.Microsoft Power Query provides a powerful "get data" experience that encompasses many features. К ключевым возможностям Power Query относятся фильтрация и объединение данных, позволяющие комбинировать данные из одного или нескольких поддерживаемых источников данных из обширной коллекции.A core capability of Power Query is to filter and combine, that is, to "mash-up" data from one or more of a rich collection of supported data sources. Для выражения всех подобных комбинаций данных используется язык формул Power Query (формально известный как язык M).Any such data mashup is expressed using the Power Query Formula Language (informally known as "M"). Power Query внедряет документы M в книги Excel и Power BI, чтобы обеспечить повторяемое объединение данных.Power Query embeds M documents in Excel and Power BI workbooks to enable repeatable mashup of data.

В этом документе содержится спецификация для M. После краткого введения, цель которого предоставить ознакомительные сведения о языке, в документе подробно рассматривается язык в нескольких последовательных шагах:This document provides the specification for M. After a brief introduction that aims at building some first intuition and familiarity with the language, the document covers the language precisely in several progressive steps:

  1. Лексическая структура определяет набор текстов, которые являются лексически допустимыми.The lexical structure defines the set of texts that are lexically valid.

  2. Значения, выражения, среды и переменные, идентификаторы и модель оценки, которые образуют основные понятия языка.Values, expressions, environments and variables, identifiers, and the evaluation model form the language's basic concepts.

  3. Подробное описание значений, как примитивов, так и структурированных данных, определяет целевое назначение языка.The detailed specification of values, both primitive and structured, defines the target domain of the language.

  4. Значения имеют типы, которые сами по себе являются особым видом значений. Оба они характеризуют фундаментальные типы значений и содержат дополнительные метаданные, относящиеся к формам структурированных значений.Values have types, themselves a special kind of value, that both characterize the fundamental kinds of values and carry additional metadata that is specific to the shapes of structured values.

  5. Набор операторов в языке M определяет, какие типы выражений могут быть сформированы.The set of operators in M defines what kinds of expressions can be formed.

  6. Функции, другая разновидность специальных значений, предоставляют основу для обширной стандартной библиотеки для языка M и позволяют добавлять новые абстракции.Functions, another kind of special values, provide the foundation for a rich standard library for M and allow for the addition of new abstractions.

  7. Ошибки могут возникать при применении операторов или функций во время вычисления выражения.Errors can occur when applying operators or functions during expression evaluation. Несмотря на то что ошибки не являются значениями, существуют способы обработки ошибок, с помощью которых ошибки можно сопоставить обратно со значениями.While errors are not values, there are ways to handle errors that map errors back to values.

  8. Выражения let позволяют создавать дополнительные определения, используемые для построения сложных выражений в несколько небольших шагов.Let expressions allow for the introduction of auxiliary definitions used to build up complex expressions in smaller steps.

  9. Выражения if поддерживают условную оценку.If expressions support conditional evaluation.

  10. Разделы обеспечивают простой механизм модульности.Sections provide a simple modularity mechanism. (Разделы пока еще не используются Power Query.)(Sections are not yet leveraged by Power Query.)

  11. Наконец, консолидированная грамматика объединяет в себе фрагменты грамматики из других разделов этого документа в одно полное определение.Finally, a consolidated grammar collects the grammar fragments from all other sections of this document into a single complete definition.

Для теоретиков компьютерных языков: язык формул, описываемый в этом документе, является по большей части чистым, динамически типизированным, частично функционально упрощенным языком высшего порядка.For computer language theorists: the formula language specified in this document is a mostly pure, higher-order, dynamically typed, partially lazy functional language.

Выражения и значенияExpressions and values

Основной компонент в языке M — это выражение.The central construct in M is the expression. Выражение можно вычислить, возвратив одно значение.An expression can be evaluated (computed), yielding a single value.

Хотя многие значения могут быть записаны буквально в виде выражения, значение не является выражением.Although many values can be written literally as an expression, a value is not an expression. Например, вычисление выражения 1 дает значение 1, а вычисление выражений 1+1 дает значение 2.For example, the expression 1 evaluates to the value 1; the expressions 1+1 evaluates to the value 2. Это неочевидное, но важное различие.This distinction is subtle, but important. Выражения являются наборами правил для вычисления, а значения — результатами вычисления.Expressions are recipes for evaluation; values are the results of evaluation.

В следующих примерах показаны различные виды значений, доступные в M. По соглашению значение записывается в литеральной форме, в которой они будут отображаться в выражении, результатом которого является только это значение.The following examples illustrate the different kinds of values available in M. As a convention, a value is written using the literal form in which they would appear in an expression that evaluates to just that value. (Обратите внимание, что // указывает начало комментария, который продолжается до конца строки.)(Note that the // indicates the start of a comment which continues to the end of the line.)

  • Примитив — это однокомпонентное значение, например число, логическое значение, текст или значение NULL.A primitive value is single-part value, such as a number, logical, text, or null. Значение NULL может использоваться для указания отсутствия каких-либо данных.A null value can be used to indicate the absence of any data.

    123                  // A number
    true                 // A logical
    "abc"                // A text
    null                 // null value
    
  • Значение списка является упорядоченной последовательностью значений.A list value is an ordered sequence of values. M поддерживает бесконечные списки, но в случае написания в виде литерала списки имеют фиксированную длину.M supports infinite lists, but if written as a literal, lists have a fixed length. Символы фигурных скобок ({ и }) обозначают начало и конец списка.The curly brace characters { and } denote the beginning and end of a list.

    {123, true, "A"}     // list containing a number, a logical, and 
                          //     a text 
    {1, 2, 3}            // list of three numbers 
    
  • Запись представляет собой набор полей.A record is a set of fields. Поле — это пара "имя-значение", где имя является текстовым значением, уникальным в пределах записи поля.A field is a name/value pair where the name is a text value that is unique within the field's record. Литеральный синтаксис значений записи позволяет записывать имена без кавычек, в такой форме они также называются идентификаторами.The literal syntax for record values allows the names to be written without quotes, a form also referred to as identifiers. Ниже показана запись, содержащая три поля с именами "A", "B" и "C", которые имеют значения 1, 2и 3.The following shows a record containing three fields named "A", "B", and "C", which have values 1, 2, and 3.

    [ 
          A = 1,  
          B = 2,  
          C = 3 
    ]
    
  • Таблица — это набор значений, упорядоченных по столбцам (идентифицируемые по имени) и строкам.A table is a set of values organized into columns (which are identified by name), and rows. Для создания таблицы не предусмотрен литеральный синтаксис, однако существует несколько стандартных функций, которые можно использовать для создания таблиц из списков или записей.There is no literal syntax for creating a table, but there are several standard functions that can be used to create tables from lists or records.

    Пример:For example:

    #table( {"A", "B"}, { {1, 2}, {3, 4} } ) 
    

    Данный код создает таблицу следующей формы:This creates a table of the following shape:

    ОбъектA BB
    11 22
    33 44
  • Функция — это значение, которое при вызове с аргументами создает новое значение.A function is a value which, when invoked with arguments, produces a new value. Функции записываются путем перечисления параметров функции в круглых скобках, за которыми следует символ перехода =>, за которым следует определяющее функцию выражение.Function are written by listing the function's parameters in parentheses, followed by the goes-to symbol =>, followed by the expression defining the function. Это выражение обычно ссылается на параметры (по имени).That expression typically refers to the parameters (by name).

    (x, y) => (x + y) / 2`
    

Ознакомительная версияEvaluation

Модель оценки языка M базируется на модели оценки, часто применяемой в электронных таблицах, где порядок вычислений можно определить на основе зависимостей между формулами в ячейках.The evaluation model of the M language is modeled after the evaluation model commonly found in spreadsheets, where the order of calculation can be determined based on dependencies between the formulas in the cells.

Если вы ввели формулы в электронных таблицах, например в Excel, можно определить, что при вычислении указанные слева формулы дадут значения, указанные справа:If you have written formulas in a spreadsheet such as Excel, you may recognize the formulas on the left will result in the values on the right when calculated:

Формула, в результате вычисления которой выводится значение

В языке M части выражения могут ссылаться на другие части выражения по имени, и процесс оценки автоматически определит порядок вычисления выражений, на которые имеются ссылки.In M, parts of an expression can reference other parts of the expression by name, and the evaluation process will automatically determine the order in which referenced expressions are calculated.

Можно использовать запись для создания выражения, эквивалентного приведенному выше примеру электронной таблицы.We can use a record to produce an expression which is equivalent to the above spreadsheet example. При инициализации значения поля мы можем сослаться на другие поля в записи по имени поля, как показано ниже:When initializing the value of a field, we can refer to other fields within the record by using the name of the field, as follows:

[  
    A1 = A2 * 2,  
    A2 = A3 + 1,  
    A3 = 1  
]

Приведенное выше выражение эквивалентно следующему (в той части, что оба вычисляют равные значения):The above expression is equivalent to the following (in that both evaluate to equal values):

[  
    A1 = 4,  
    A2 = 2,  
    A3 = 1  
]

Записи могут содержаться в других записях или вкладываться в них.Records can be contained within, or nest, within other records. Для обращения к полям записи по имени можно использовать оператор подстановки ([]).We can use the lookup operator ([]) to access the fields of a record by name. Например, следующая запись содержит поле Sales, содержащее запись, и поле Total, которое обращается к полям FirstHalf и SecondHalf записи Sales:For example, the following record has a field named Sales containing a record, and a field named Total that accesses the FirstHalf and SecondHalf fields of the Sales record:

[  
    Sales = [ FirstHalf = 1000, SecondHalf = 1100 ], 
    Total = Sales[FirstHalf] + Sales[SecondHalf] 
]

Приведенное выше выражение эквивалентно следующему при вычислении:The above expression is equivalent to the following when it is evaluated: </span>

[  
    Sales = [ FirstHalf = 1000, SecondHalf = 1100 ], 
    Total = 2100 
]

Записи также могут содержаться в списках.Records can also be contained within lists. Чтобы обратиться к элементу списка по его числовому индексу, используйте позиционный оператор индекса ({}).We can use the positional index operator ({}) to access an item in a list by its numeric index. Для ссылки на значения в списке используется начинающийся с нуля индекс, отсчитываемый от начала списка.The values within a list are referred to using a zero-based index from the beginning of the list. Например, индексы 0 и 1 используются для ссылки на первый и второй элементы в списке ниже:For example, the indexes 0 and 1 are used to reference the first and second items in the list below:

[ 
    Sales =  
        {  
            [  
                Year = 2007,  
                FirstHalf = 1000,  
                SecondHalf = 1100, 
                Total = FirstHalf + SecondHalf // 2100 
            ], 
            [  
                Year = 2008,  
                FirstHalf = 1200,  
                SecondHalf = 1300, 
                Total = FirstHalf + SecondHalf // 2500 
            ]  
        }, 
    TotalSales = Sales{0}[Total] + Sales{1}[Total] // 4600 
]

Выражения элементов списка и записи (а также выражения let, представленные ниже) оцениваются с помощью отложенных вычислений, что означает, что они оцениваются только по мере необходимости.List and record member expressions (as well as let expressions, introduced further below) are evaluated using lazy evaluation, which means that they are evaluated only as needed. Все остальные выражения оцениваются с помощью безотложного вычисления, то есть сразу же при их обнаружении в процессе оценки.All other expressions are evaluated using eager evaluation, which means that they are evaluated immediately, when encountered during the evaluation process. При этом следует помнить, что оценка выражения записи или списка возвратит значение записи или списка, которое помнит соответствующе поля записи или элементы списка, которые требуется вычислить при необходимости (с помощью операторов индекса или подстановки).A good way to think about this is to remember that evaluating a list or record expression will return a list or record value that itself remembers how its list items or record fields need to be computed, when requested (by lookup or index operators).

ФункцииFunctions

В языке M функция — это сопоставление набора входных значений с одним выходным значением.In M, a function is a mapping from a set of input values to a single output value. Функция записывается путем именования требуемого набора входных значений (параметров функции) и последующего предоставления выражения, которое будет вычислять результат функции с использованием этих входных значений (основная часть функции) после символа перехода (=>).A function is written by first naming the required set of input values (the parameters to the function) and then providing an expression that will compute the result of the function using those input values (the body of the function) following the goes-to (=>) symbol. Пример:For example:

(x) => x + 1                    // function that adds one to a value 
(x, y) =>  x + y                // function that adds two values

Функция — это значение, аналогичное числу или текстовому значению.A function is a value just like a number or a text value. В следующем примере показана функция, являющаяся значением поля "Add", которая затем вызывается или выполняется из нескольких других полей.The following example shows a function which is the value of an Add field which is then invoked, or executed, from several other fields. При вызове функции указывается набор значений, которые логически подставляются для требуемого набора входных значений в выражении тела функции.When a function is invoked, a set of values are specified which are logically substituted for the required set of input values within the function body expression.

[ 
    Add = (x, y) => x + y,
    OnePlusOne = Add(1, 1),     // 2 
    OnePlusTwo = Add(1, 2)      // 3
]

БиблиотекаLibrary

Язык M включает общий набор определений, доступных для использования в выражении, который именуется стандартной библиотекой или просто библиотекой для краткости.M includes a common set of definitions available for use from an expression called the standard library, or just library for short. Эти определения состоят из набора именованных значений.These definitions consist of a set of named values. Имена значений, предоставленных в библиотеке, можно использовать в выражении без необходимости определять их явным образом в выражении.The names of values provided by a library are available for use within an expression without having been defined explicitly by the expression. Пример:For example:

Number.E                        // Euler's number e (2.7182...) 
Text.PositionOf("Hello", "ll")  // 2

ОператорыOperators

Язык M включает набор операторов, которые можно использовать в выражениях.M includes a set of operators that can be used in expressions. Операторы применяются к операндам для формирования символьных выражений.Operators are applied to operands to form symbolic expressions. Например, в выражении 1 + 2 числа 1 и 2 являются операндами, а оператор представлен оператором сложения (+).For example, in the expression 1 + 2 the numbers 1 and 2 are operands and the operator is the addition operator (+).

Значение оператора может меняться в зависимости от типа значений операндов.The meaning of an operator can vary depending on what kind of values its operands are. Например, оператор сложения можно использовать с другими видами значений, отличными от чисел:For example, the plus operator can be used with other kinds of values than numbers:

1 + 2                   // numeric addition: 3 
#time(12,23,0) + #duration(0,0,2,0) 
                        // time arithmetic: #time(12,25,0)

Еще один пример оператора с операндом в зависимости от значения — оператор комбинирования (&):Another example of an operator with operand-depending meaning is the combination operator (&):

"A" & "BC"              // text concatenation: "ABC" 
{1} & {2, 3}            // list concatenation: {1, 2, 3} 
[ a = 1 ] & [ b = 2 ]   // record merge: [ a = 1, b = 2 ]

Обратите внимание, что оператор может поддерживать не все сочетания значений.Note that not all combinations of values may be supported by an operator. Пример:For example:

1 + "2"  // error: adding number and text is not supported

Выражения, при вычислении которых возникают неопределенные условия оператора, обрабатываются как ошибки.Expressions that, when evaluated, encounter undefined operator conditions evaluate to errors. Дополнительные сведения об ошибках в языке М представлены ниже.More on errors in M later.

МетаданныеMetadata

Метаданные — это сведения о значении, которое связано со значением.Metadata is information about a value that is associated with a value. Метаданные представлены в виде значения записи, которое называется записью метаданных.Metadata is represented as a record value, called a metadata record. Поля записи метаданных можно использовать для хранения метаданных значения.The fields of a metadata record can be used to store the metadata for a value.

Каждое значение имеет запись метаданных.Every value has a metadata record. Если значение записи метаданных не указано, то запись метаданных пуста (не содержит поля).If the value of the metadata record has not been specified, then the metadata record is empty (has no fields).

Записи метаданных предоставляют способ связать дополнительную информацию с любым видом значения ненавязчивым способом.Metadata records provide a way to associate additional information with any kind of value in an unobtrusive way. Связывание записи метаданных со значением не приводит к изменению значения или его поведения.Associating a metadata record with a value does not change the value or its behavior.

Значение записи метаданных y связывается с существующим значением x с помощью синтаксиса x meta y.A metadata record value y is associated with an existing value x using the syntax x meta y. Например, следующая связывает запись метаданных с полями Rating и Tags с текстовым значением "Mozart":For example, the following associates a metadata record with Rating and Tags fields with the text value "Mozart":

"Mozart" meta [ Rating = 5, Tags = {"Classical"} ]

Для значений, которые уже содержат непустую запись метаданных, результат применения мета заключается в вычислении слияния записей существующей и новой записей метаданных.For values that already carry a non-empty metadata record, the result of applying meta is that of computing the record merge of the existing and the new metadata record. Например, следующие два выражения эквивалентны друг другу и предыдущему выражению:For example, the following two expressions are equivalent to each other and to the previous expression:

("Mozart" meta [ Rating = 5 ]) meta [ Tags = {"Classical"} ] 
"Mozart" meta ([ Rating = 5 ] & [ Tags = {"Classical"} ])

Обратиться к записи метаданных для указанного значения можно с помощью функции Value.Metadata.A metadata record can be accessed for a given value using the Value.Metadata function. В следующем примере выражение в поле ComposerRating обращается к записи метаданных значения в поле Composer, а затем обращается к полю Rating записи метаданных.In the following example, the expression in the ComposerRating field accesses the metadata record of the value in the Composer field, and then accesses the Rating field of the metadata record.

[ 
    Composer = "Mozart" meta [ Rating = 5, Tags = {"Classical"} ], 
    ComposerRating = Value.Metadata(Composer)[Rating] // 5
]

Выражение letLet expression

Многие из приведенных выше примеров содержат в результате выражения все литеральные значения выражения.Many of the examples shown so far have included all the literal values of the expression in the result of the expression. Выражение let позволяет вычислить, снабдить именами набор значений, а затем использовать их в последующем выражении, которое следует за оператором in.The let expression allows a set of values to be computed, assigned names, and then used in a subsequent expression that follows the in. Например, в нашем примере данных о продажах можно сделать следующее:For example, in our sales data example, we could do:

let 
    Sales2007 =  
        [  
            Year = 2007,  
            FirstHalf = 1000,  
            SecondHalf = 1100, 
            Total = FirstHalf + SecondHalf // 2100 
        ], 
    Sales2008 =  
        [  
            Year = 2008,  
            FirstHalf = 1200,  
            SecondHalf = 1300, 
            Total = FirstHalf + SecondHalf // 2500 
        ] 
  in Sales2007[Total] + Sales2008[Total] // 4600

Результатом приведенного выше выражения является числовое значение (4600), вычисленное на основе значений, привязанных к именам Sales2007 и Sales2008.The result of the above expression is a number value (4600) which was computed from the values bound to the names Sales2007 and Sales2008.

Выражение ifIf expression

Выражение if осуществляет выбор между двумя выражениями на основе логического условия.The if expression selects between two expressions based on a logical condition. Пример:For example:

if 2 > 1 then
    2 + 2
else  
    1 + 1

Первое выражение (2 + 2) выбирается, если логическое выражение (2 > 1) истинно, а второе выражение (1 + 1) выбирается, если оно ложно.The first expression (2 + 2) is selected if the logical expression (2 > 1) is true, and the second expression (1 + 1) is selected if it is false. Выбранное выражение (в данном случае 2 + 2) вычисляется и становится результатом выражения if (4).The selected expression (in this case 2 + 2) is evaluated and becomes the result of the if expression (4).

ошибкиErrors

Ошибка в языке M означает, что при вычислении выражения не удалось получить значение.An error is an indication that the process of evaluating an expression could not produce a value.

Ошибки выдаются операторами и функциями, сталкивающимися с условиями ошибки, либо с помощью выражения error.Errors are raised by operators and functions encountering error conditions or by using the error expression. Ошибки обрабатываются с помощью выражения try.Errors are handled using the try expression. При возникновении ошибки указывается значение, которое можно использовать для указания причины возникновения ошибки.When an error is raised, a value is specified that can be used to indicate why the error occurred.

let Sales = 
    [ 
        Revenue = 2000, 
        Units = 1000, 
        UnitPrice = if Units = 0 then error "No Units"
                    else Revenue / Units 
    ], 
    UnitPrice = try Number.ToText(Sales[UnitPrice])
in "Unit Price: " & 
    (if UnitPrice[HasError] then UnitPrice[Error][Message]
    else UnitPrice[Value])

Приведенный выше пример обращается к полю Sales[UnitPrice] и форматирует значение, формирующее результат:The above example accesses the Sales[UnitPrice] field and formats the value producing the result:

"Unit Price: 2"

Если бы поле Units было равно нулю, то поле UnitPrice привело бы к возникновению ошибки, которая была бы обработана выражением try.If the Units field had been zero, then the UnitPrice field would have raised an error which would have been handled by the try. В этом случае итоговое значение имело бы следующий вид:The resulting value would then have been:

"No Units"

Выражение try преобразует надлежащие значения и ошибки в значение записи, которое указывает, обрабатывало ли выражение try ошибку или нет, и правильное значение либо запись об ошибке, извлеченные при обработке ошибки.A try expression converts proper values and errors into a record value that indicates whether the try expression handled and error, or not, and either the proper value or the error record it extracted when handling the error. Например, рассмотрим следующее выражение, которое вызывает ошибку и затем сразу же обрабатывает ее:For example, consider the following expression that raises an error and then handles it right away:

try error "negative unit count"

Результатом вычисления этого выражения является следующее вложенное значение записи, поясняющее подстановки полей [HasError], [Error] и [Message] в приведенном ранее примере с ценой на единицу.This expression evaluates to the following nested record value, explaining the [HasError], [Error], and [Message] field lookups in the unit-price example before.

[ 
    HasError = true, 
    Error = 
        [ 
            Reason = "Expression.Error", 
            Message = "negative unit count", 
            Detail = null 
        ] 
]

Распространена замена ошибок значениями по умолчанию.A common case is to replace errors with default values. Чтобы добиться того же, но в компактной форме, можно использовать выражение try с необязательным предложением otherwise:The try expression can be used with an optional otherwise clause to achieve just that in a compact form:

try error "negative unit count" otherwise 42 
// 42